kellerkind 0.1.2 → 0.2.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/.travis.yml +7 -0
- data/README.md +28 -2
- data/VERSION +1 -1
- data/bin/kellerkind +40 -9
- data/kellerkind.gemspec +12 -6
- data/lib/kellerkind/core/configuration.rb +22 -10
- data/lib/kellerkind/core/set.rb +0 -11
- data/lib/kellerkind/dependencies.rb +2 -1
- data/lib/kellerkind/modules/implementations/log_file.rb +44 -0
- data/lib/kellerkind/{database → modules/implementations}/mongo.rb +7 -7
- data/lib/kellerkind/modules/log.rb +25 -0
- data/lib/kellerkind/modules/modules.rb +3 -0
- data/lib/kellerkind/modules/mongodb.rb +46 -0
- data/lib/kellerkind/system/compress.rb +48 -22
- data/lib/kellerkind/system/process.rb +70 -0
- data/lib/kellerkind/system/runner.rb +17 -44
- data/spec/fixtures/mongodb.js +1 -1
- data/spec/kellerkind/modules/implementations/log_file_spec.rb +95 -0
- data/spec/kellerkind/{database → modules/implementations}/mongo_spec.rb +2 -1
- data/spec/kellerkind/modules/mongodb_spec.rb +43 -0
- data/spec/kellerkind/system/compress_spec.rb +12 -9
- metadata +13 -7
- data/Gemfile.lock +0 -73
- data/spec/kellerkind_spec.rb +0 -7
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# kellerkind
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/dsci/kellerkind)
|
4
|
+
|
5
|
+
Kellerkind is a Ruby application that runs several backup actions.
|
6
|
+
|
7
|
+
|Type | Status| Cli flag
|
8
|
+
|:----|-------:|--------:|
|
9
|
+
|MongoDB Dumps | Done | ```--type mongodb```|
|
10
|
+
|(Log)File Backup | Done | ```--type files ```|
|
11
|
+
|
4
12
|
|
5
13
|
It should be used with its cli but it's also possible to use it with its API.
|
6
14
|
|
@@ -22,12 +30,30 @@ to the arguments you could specify.
|
|
22
30
|
|
23
31
|
**Example**
|
24
32
|
|
33
|
+
*Dumping a Mongo database and compressing the dump*
|
34
|
+
|
25
35
|
```
|
26
|
-
kellerkind --mongo-db appDatabase --mongo-host linus.mongohq.com --mongo-port 10010 --mongo-username myUser --mongo-password myCrypticPassword --compress true --out $HOME/tmp/mongodump
|
36
|
+
kellerkind --type mongodb --mongo-db appDatabase --mongo-host linus.mongohq.com --mongo-port 10010 --mongo-username myUser --mongo-password myCrypticPassword --compress true --out $HOME/tmp/mongodump
|
27
37
|
```
|
28
38
|
|
29
39
|
Dumps a database hosted at MongoHQ to <code>$HOME/tmp/mongodump</code> and create a tar file of this dump.
|
30
40
|
|
41
|
+
*Backing up several log files*
|
42
|
+
|
43
|
+
```
|
44
|
+
kellerkind --type log --files $HOME/rails/my_app/log/production.log $HOME/logs/unicorn.stdout.log --out $HOME/tmp/log_backups --verbose true
|
45
|
+
```
|
46
|
+
|
47
|
+
Backups and compresses ```$HOME/rails/my_app/log/production.log``` and ```$HOME/logs/unicorn.stdout.log``` to ```$HOME/tmp/log_backups```, deletes the original files and recreates them as blank files.
|
48
|
+
|
49
|
+
## Tests
|
50
|
+
|
51
|
+
Run
|
52
|
+
|
53
|
+
```
|
54
|
+
rspec spec/
|
55
|
+
```
|
56
|
+
|
31
57
|
## Contributing to kellerkind
|
32
58
|
|
33
59
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1
|
1
|
+
0.2.1
|
data/bin/kellerkind
CHANGED
@@ -5,15 +5,23 @@ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
|
5
5
|
require 'kellerkind'
|
6
6
|
|
7
7
|
REQUIRED_ARGS = {
|
8
|
-
:
|
9
|
-
|
10
|
-
}
|
8
|
+
:mongodb => {
|
9
|
+
:mongo_db => %Q{You must specify a mongo database! },
|
10
|
+
:out => %Q{You must specify a path the dump should saved to! }
|
11
|
+
},
|
12
|
+
:log => {
|
13
|
+
:files => %Q{You must specifiy at least one file! }
|
14
|
+
}
|
15
|
+
|
16
|
+
}
|
17
|
+
|
11
18
|
|
12
19
|
opts = Trollop::options do
|
13
20
|
banner <<-EOS
|
14
|
-
|
21
|
+
Archiving tool.
|
15
22
|
|
16
|
-
Dumps mongodb databases and archives them.
|
23
|
+
Dumps mongodb databases and archives them. Compresses files and archives
|
24
|
+
them. Nothing more. Neat, isn't it?
|
17
25
|
EOS
|
18
26
|
|
19
27
|
opt :mongo_db, "mongo database to dump", :type => :string
|
@@ -23,15 +31,38 @@ opts = Trollop::options do
|
|
23
31
|
opt :mongo_password, "mongo password", :type => :string
|
24
32
|
opt :mongo_port, "mongo server port", :type => :string,
|
25
33
|
:default => "27017"
|
26
|
-
opt :out, "path
|
27
|
-
|
28
|
-
|
34
|
+
opt :out, "path output directory", :type => :string
|
35
|
+
|
36
|
+
opt :compress, "use gzip compression? (files are always gzipped)",
|
37
|
+
:type => :boolean,
|
38
|
+
:default => false
|
39
|
+
|
29
40
|
opt :remove_dump, "remove dump after compression?", :type => :boolean,
|
30
41
|
:default => true
|
42
|
+
opt :files, "files to compress", :type => :strings
|
43
|
+
|
44
|
+
opt :type, "the type kellerkind should handles: [mongodbd, log]",
|
45
|
+
:type => :string,
|
46
|
+
:default => "mongodb"
|
47
|
+
|
48
|
+
opt :recreate, "Recreate files after moving and compressing (only effects :files type)",
|
49
|
+
:type => :boolean,
|
50
|
+
:default => true
|
51
|
+
|
52
|
+
opt :verbose, "Verbose output",
|
53
|
+
:type => :boolean,
|
54
|
+
:default => false
|
31
55
|
end
|
32
56
|
|
33
57
|
REQUIRED_ARGS.each_pair do |key,value|
|
34
|
-
|
58
|
+
type = key
|
59
|
+
type_config = value
|
60
|
+
used_type = opts[:type]
|
61
|
+
if used_type.eql?(type.to_s)
|
62
|
+
type_config.each_pair do |type_key, type_value|
|
63
|
+
Trollop::die type_key, type_value unless opts[type_key]
|
64
|
+
end
|
65
|
+
end
|
35
66
|
end
|
36
67
|
|
37
68
|
Kellerkind::Runner.exec(opts)
|
data/kellerkind.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "kellerkind"
|
8
|
-
s.version = "0.1
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Daniel Schmidt"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-11-18"
|
13
13
|
s.description = "Dumps mongodb databases and archives them."
|
14
14
|
s.email = "dsci@code79.net"
|
15
15
|
s.executables = ["kellerkind"]
|
@@ -20,8 +20,8 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.files = [
|
21
21
|
".document",
|
22
22
|
".rspec",
|
23
|
+
".travis.yml",
|
23
24
|
"Gemfile",
|
24
|
-
"Gemfile.lock",
|
25
25
|
"LICENSE.txt",
|
26
26
|
"README.md",
|
27
27
|
"Rakefile",
|
@@ -32,18 +32,24 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/kellerkind/core/configuration.rb",
|
33
33
|
"lib/kellerkind/core/ext.rb",
|
34
34
|
"lib/kellerkind/core/set.rb",
|
35
|
-
"lib/kellerkind/database/mongo.rb",
|
36
35
|
"lib/kellerkind/dependencies.rb",
|
36
|
+
"lib/kellerkind/modules/implementations/log_file.rb",
|
37
|
+
"lib/kellerkind/modules/implementations/mongo.rb",
|
38
|
+
"lib/kellerkind/modules/log.rb",
|
39
|
+
"lib/kellerkind/modules/modules.rb",
|
40
|
+
"lib/kellerkind/modules/mongodb.rb",
|
37
41
|
"lib/kellerkind/system/compress.rb",
|
38
42
|
"lib/kellerkind/system/die.rb",
|
39
43
|
"lib/kellerkind/system/lock.rb",
|
44
|
+
"lib/kellerkind/system/process.rb",
|
40
45
|
"lib/kellerkind/system/runner.rb",
|
41
46
|
"spec/fixtures/mongodb.js",
|
42
|
-
"spec/kellerkind/
|
47
|
+
"spec/kellerkind/modules/implementations/log_file_spec.rb",
|
48
|
+
"spec/kellerkind/modules/implementations/mongo_spec.rb",
|
49
|
+
"spec/kellerkind/modules/mongodb_spec.rb",
|
43
50
|
"spec/kellerkind/system/compress_spec.rb",
|
44
51
|
"spec/kellerkind/system/lock_spec.rb",
|
45
52
|
"spec/kellerkind/tmp/.gitkeep",
|
46
|
-
"spec/kellerkind_spec.rb",
|
47
53
|
"spec/spec_helper.rb"
|
48
54
|
]
|
49
55
|
s.homepage = "http://github.com/dsci/kellerkind"
|
@@ -1,28 +1,28 @@
|
|
1
1
|
module Kellerkind
|
2
|
-
|
3
|
-
# Public: Various methods useful for configure Kellerkind.
|
2
|
+
|
3
|
+
# Public: Various methods useful for configure Kellerkind.
|
4
4
|
module Config
|
5
5
|
extend self
|
6
6
|
|
7
|
-
|
7
|
+
|
8
8
|
# Public: Gets the prefix that is use in the cli for database options.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# Returns a regular expression.
|
11
11
|
def db_prefix
|
12
12
|
/mongo_/
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
|
16
16
|
# Public: Gets the name of the command line executable to use for
|
17
|
-
# dumping.
|
18
|
-
#
|
17
|
+
# dumping.
|
18
|
+
#
|
19
19
|
# Returns name of executable as String.
|
20
20
|
def db_dump_cmd
|
21
21
|
"mongodump"
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
# Public: Gets the path to the lock dir to mark process running.
|
24
|
+
|
25
|
+
# Public: Gets the path to the lock dir to mark process running.
|
26
26
|
# Note that just one kellerkind process is runnable.
|
27
27
|
def lock_dir
|
28
28
|
File.join(Dir.home, "tmp")
|
@@ -60,5 +60,17 @@ module Kellerkind
|
|
60
60
|
%Q{ -- Dumping of #{database} done ...}
|
61
61
|
end
|
62
62
|
|
63
|
+
# Internal: Sets if Kellerkind should be talkative or not.
|
64
|
+
#
|
65
|
+
# flag - Boolean, true if Kellerkind should generate output, false if not.
|
66
|
+
def verbose_output=(flag)
|
67
|
+
@verbose_output = flag
|
68
|
+
end
|
69
|
+
|
70
|
+
# Internal: Checks if Kellerkind should be verbose or not.
|
71
|
+
def verbose?
|
72
|
+
@verbose_output
|
73
|
+
end
|
74
|
+
|
63
75
|
end
|
64
|
-
end
|
76
|
+
end
|
data/lib/kellerkind/core/set.rb
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
module Kellerkind
|
2
2
|
class Set
|
3
3
|
include Virtus
|
4
|
-
|
5
|
-
protected
|
6
|
-
|
7
|
-
def init_instance(options)
|
8
|
-
options.each_pair do |key,value|
|
9
|
-
instance_attr = key.to_s.split(Kellerkind::Config.db_prefix).last
|
10
|
-
if instance_attr.to_sym.in?(attributes.keys)
|
11
|
-
self.send("#{instance_attr}=", value)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
4
|
end
|
16
5
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Kellerkind
|
4
|
+
|
5
|
+
# Public: Compresses/Backups a bunch of files.
|
6
|
+
# All methods are module methods and should be called on the Math module.
|
7
|
+
#
|
8
|
+
class LogFile < Set
|
9
|
+
|
10
|
+
# A list of files (at least one)
|
11
|
+
attribute :files, Array
|
12
|
+
# File path location for compressed backups
|
13
|
+
attribute :out, String
|
14
|
+
# Indicator if list of files should be recreated after compressing as
|
15
|
+
# blank file.
|
16
|
+
attribute :recreate, Boolean
|
17
|
+
|
18
|
+
# Public: Compresses the backup, removes the files and (optional) recreates
|
19
|
+
# them as blank files.
|
20
|
+
def archive
|
21
|
+
files.each do |path|
|
22
|
+
path_obj = Pathname.new(path)
|
23
|
+
path_name = path_obj.dirname.to_s
|
24
|
+
compress = Kellerkind::Compress.new(:target_path => out,
|
25
|
+
:source_path => path,
|
26
|
+
:tarball_prefix => path_obj.basename.to_s)
|
27
|
+
compress.find_at_source_path = true
|
28
|
+
if File.exists?(path)
|
29
|
+
Kellerkind::Process.verbose(:start_compressing)
|
30
|
+
compress.gzip
|
31
|
+
if File.exists?("#{path_name}/#{compress.tarball_name}")
|
32
|
+
Kellerkind::Process.verbose(:finished_compressing)
|
33
|
+
FileUtils.mv("#{path_name}/#{compress.tarball_name}",
|
34
|
+
"#{out}/#{compress.tarball_name}")
|
35
|
+
FileUtils.rm_rf(path)
|
36
|
+
FileUtils.touch(path) if self.recreate
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Kellerkind
|
2
|
-
|
3
|
-
# Public: Dumps a MongoDb database.
|
2
|
+
|
3
|
+
# Public: Dumps a MongoDb database.
|
4
4
|
#
|
5
5
|
# For more see mongodump --help
|
6
6
|
class Mongo < Set
|
@@ -22,20 +22,20 @@ module Kellerkind
|
|
22
22
|
init_instance(options) unless options.empty?
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
|
26
26
|
# Public: Dumps the database by using a stream to the underlying
|
27
|
-
# operation system.
|
28
|
-
#
|
27
|
+
# operation system.
|
28
|
+
#
|
29
29
|
def dump_database
|
30
30
|
cmd = %Q{`which #{Kellerkind::Config.db_dump_cmd}` #{dump_argument_list}}
|
31
31
|
out = IO.popen(cmd)
|
32
32
|
out.readlines.join(" ")
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
|
36
36
|
# Public: Builds an argument list for mongodump by taking only values
|
37
37
|
# existing in #attributes
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# Returns the argument list string.
|
40
40
|
def dump_argument_list
|
41
41
|
usable_line_args = attributes.select{|k,v| not v.nil? }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kellerkind
|
2
|
+
|
3
|
+
# Public: (Log)File Kellerkind module that compresses a bunch of files,
|
4
|
+
# removes and recreates blank files of them.
|
5
|
+
class Log
|
6
|
+
|
7
|
+
# Public: Starts compressing a bunch of logfiles, removes and recreates
|
8
|
+
# blank files of them - if --recreate is true.
|
9
|
+
#
|
10
|
+
# options={} - An options Hash to refine log file process.
|
11
|
+
# :paths - A list fo file paths that should be compressed
|
12
|
+
# and moved.
|
13
|
+
# :out - The path the files should be moved to
|
14
|
+
# :recreate - Indictator if the files should be renewed as
|
15
|
+
# blank file after compressing.
|
16
|
+
#
|
17
|
+
# Returns the duplicated String.
|
18
|
+
def self.exec(options={})
|
19
|
+
Kellerkind::Process.locked?
|
20
|
+
Kellerkind::Process.lock
|
21
|
+
LogFile.new(options).archive
|
22
|
+
Kellerkind::Process.unlock
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Kellerkind
|
2
|
+
|
3
|
+
# Public: MongoDB Kellerkind module that dumps a MongoDB database and
|
4
|
+
# compresses it into a tarball (if --compress is true).
|
5
|
+
class Mongodb
|
6
|
+
|
7
|
+
# Public: Starts dumping and compressing the MongoDB database specified in
|
8
|
+
# options.
|
9
|
+
#
|
10
|
+
# options - A Hash to refine the dumping and compressing process
|
11
|
+
# :out - The target directory the (compressed) dump is saved to
|
12
|
+
# :mongo_db - The MongoDB database
|
13
|
+
# :compress - Compress the dump [true|false]
|
14
|
+
# :remove_dump - Remove the dump after compressing it
|
15
|
+
#
|
16
|
+
def self.exec(options)
|
17
|
+
Kellerkind::Process.locked?
|
18
|
+
Kellerkind::Process.lock
|
19
|
+
mongo = Mongo.new(options)
|
20
|
+
Kellerkind::Process.verbose(:start_dumping)
|
21
|
+
mongo.dump_database
|
22
|
+
if options[:compress]
|
23
|
+
compress = Compress.new(:source_path => options[:out],
|
24
|
+
:target_path => options[:out],
|
25
|
+
:tarball_prefix =>options[:mongo_db])
|
26
|
+
if File.exists?(File.join(options[:out], options[:mongo_db]))
|
27
|
+
Kellerkind::Process.verbose(:start_compressing)
|
28
|
+
compress.gzip
|
29
|
+
if compress.succeeded?
|
30
|
+
Kellerkind::Process.verbose(:finished_compressing)
|
31
|
+
if options[:remove_dump]
|
32
|
+
Kellerkind::Process.verbose(:remove_dump)
|
33
|
+
FileUtils.rm_rf(File.join(options[:out],mongo.db))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
Kellerkind::Process.unlock
|
38
|
+
die(DUMP_NOT_SUCCEEDED_WARNING)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Kellerkind::Process.unlock
|
43
|
+
Kellerkind::Process.verbose(:finished_dumping, mongo.db)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -2,57 +2,83 @@ require 'zlib'
|
|
2
2
|
require 'archive/tar/minitar'
|
3
3
|
|
4
4
|
module Kellerkind
|
5
|
-
|
6
|
-
# Public: Compresses a mongodb dump directory by using Gzip and tar.
|
5
|
+
|
6
|
+
# Public: Compresses a mongodb dump directory by using Gzip and tar.
|
7
7
|
class Compress < Set
|
8
8
|
|
9
9
|
include Archive::Tar
|
10
10
|
|
11
11
|
# Path where dump is located (parent direcotry of the dump)
|
12
|
-
attribute :path, String
|
12
|
+
# attribute :path, String
|
13
13
|
# Database name which equals the dumps directory name
|
14
|
-
|
14
|
+
# attribute :database_name, String
|
15
|
+
|
16
|
+
attribute :target_path, String
|
17
|
+
attribute :source_path, String
|
18
|
+
attribute :tarball_prefix, String
|
19
|
+
|
20
|
+
# Public: Duplicate some text an arbitrary number of times.
|
21
|
+
#
|
22
|
+
# Returns the duplicated String.
|
23
|
+
def find_at_source_path
|
24
|
+
@find_at_source_path ||= false
|
25
|
+
end
|
15
26
|
|
16
|
-
|
17
|
-
#
|
27
|
+
# Public: Duplicate some text an arbitrary number of times.
|
28
|
+
#
|
29
|
+
# flag -
|
30
|
+
#
|
31
|
+
# Returns the duplicated String.
|
32
|
+
def find_at_source_path=(flag)
|
33
|
+
@find_at_source_path = flag
|
34
|
+
end
|
35
|
+
|
36
|
+
# Public: Initialises compressing of the dumps directory.
|
18
37
|
def gzip
|
19
38
|
traverse_and_gzip
|
20
39
|
end
|
21
40
|
|
22
|
-
|
23
|
-
#
|
24
|
-
#
|
41
|
+
# Public: Checks if tar file exists.
|
42
|
+
#
|
25
43
|
# If tar file exists we assume compressing succeeds
|
26
44
|
#
|
27
45
|
# Returns true if file exists otherwise false.
|
28
46
|
def succeeded?
|
29
|
-
File.exists?(File.join(self.
|
47
|
+
File.exists?(File.join(self.target_path, @actual_tar_name))
|
48
|
+
end
|
49
|
+
|
50
|
+
def tarball_name
|
51
|
+
"#{self.tarball_prefix}_#{Time.now.to_i}.tar.gz"
|
30
52
|
end
|
31
53
|
|
32
54
|
private
|
33
55
|
|
34
56
|
def traverse_and_gzip
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
tgz = Zlib::GzipWriter.new(db_dump_gz_file)
|
39
|
-
Minitar.pack(file, tgz)
|
40
|
-
end
|
41
|
-
end
|
57
|
+
Find.find(self.source_path).each do |file|
|
58
|
+
tgz = Zlib::GzipWriter.new(db_dump_gz_file)
|
59
|
+
Minitar.pack(file, tgz)
|
42
60
|
end
|
43
61
|
end
|
44
62
|
|
45
|
-
def tarball_name
|
46
|
-
"#{self.database_name}_#{Time.now.to_i}.tar.gz"
|
47
|
-
end
|
48
|
-
|
49
63
|
def db_dump_gz_file
|
50
64
|
File.open(tar_location, 'wb')
|
51
65
|
end
|
52
66
|
|
53
67
|
def tar_location
|
54
68
|
@actual_tar_name = tarball_name
|
55
|
-
File.join(
|
69
|
+
File.join(define_lookup_path, @actual_tar_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def define_lookup_path
|
73
|
+
if find_at_source_path
|
74
|
+
if File.directory?(self.source_path)
|
75
|
+
self.source_path
|
76
|
+
else
|
77
|
+
File.dirname(self.source_path)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
self.target_path
|
81
|
+
end
|
56
82
|
end
|
57
83
|
|
58
84
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Kellerkind
|
2
|
+
module Process
|
3
|
+
extend Die
|
4
|
+
|
5
|
+
class Output
|
6
|
+
def self.outputs
|
7
|
+
{
|
8
|
+
:start_dumping => lambda do
|
9
|
+
puts Kellerkind::Config.start_dumping
|
10
|
+
end,
|
11
|
+
:start_compressing => lambda do
|
12
|
+
puts Kellerkind::Config.start_compressing
|
13
|
+
end,
|
14
|
+
:finished_compressing => lambda do
|
15
|
+
puts Kellerkind::Config.finished_compressing
|
16
|
+
end,
|
17
|
+
:remove_dump => lambda do
|
18
|
+
puts Kellerkind::Config.remove_dump
|
19
|
+
end,
|
20
|
+
:finished_dumping => lambda do |db_name|
|
21
|
+
puts Kellerkind::Config.finished_dumping(db_name)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.respond_to?(meth_name)
|
27
|
+
outputs.has_key?(meth_name) || super
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.method_missing(meth_name, *args, &block)
|
31
|
+
if outputs.has_key?(meth_name)
|
32
|
+
output = outputs[meth_name]
|
33
|
+
if Kellerkind::Config.verbose?
|
34
|
+
output.call(*args) if output.arity == 1
|
35
|
+
output.call unless output.arity == 1
|
36
|
+
end
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
PROCESS_LOCKED_WARNING = <<-WARNING
|
45
|
+
kellerkind.lock find! Make sure that there isn't another kellerkind process running!
|
46
|
+
WARNING
|
47
|
+
|
48
|
+
DUMP_NOT_SUCCEEDED_WARNING = <<-WARNING
|
49
|
+
No dump found. It seems dumping failed.
|
50
|
+
WARNING
|
51
|
+
|
52
|
+
def self.lock
|
53
|
+
Kellerkind::Lock.lock_process
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.unlock
|
57
|
+
Kellerkind::Lock.unlock_process
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.locked?
|
61
|
+
die(PROCESS_LOCKED_WARNING) if File.exists?(Kellerkind::Config.lock_path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.verbose(*args)
|
65
|
+
kind = args.shift
|
66
|
+
Kellerkind::Process::Output.send(kind, *args)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -1,56 +1,29 @@
|
|
1
1
|
module Kellerkind
|
2
|
+
|
3
|
+
# Public: Runs the Kellerkind modules depending of the --type commandline
|
4
|
+
# argument.
|
2
5
|
class Runner
|
3
6
|
extend Die
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
No dump found. It seems dumping failed.
|
11
|
-
WARNING
|
12
|
-
|
8
|
+
# Public: Executes a Kellerkind module.
|
9
|
+
#
|
10
|
+
# options={} - An optins Hash to define the behaviour of the Kellerkind
|
11
|
+
# modules. That is - in fact - the command line arguments.
|
12
|
+
#
|
13
13
|
def self.exec(options={})
|
14
|
-
|
15
|
-
|
16
|
-
mongo = Mongo.new(options)
|
17
|
-
puts Kellerkind::Config.start_dumping
|
18
|
-
mongo.dump_database
|
19
|
-
if options[:compress]
|
20
|
-
compress = Compress.new(:path => options[:out],
|
21
|
-
:database_name =>options[:mongo_db])
|
22
|
-
if File.exists?(File.join(options[:out], options[:mongo_db]))
|
23
|
-
puts Kellerkind::Config.start_compressing
|
24
|
-
compress.gzip
|
25
|
-
if compress.succeeded?
|
26
|
-
puts Kellerkind::Config.finished_compressing
|
27
|
-
if options[:remove_dump]
|
28
|
-
puts Kellerkind::Config.remove_dump
|
29
|
-
FileUtils.rm_rf(File.join(options[:out],mongo.db))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
else
|
33
|
-
unlock_process
|
34
|
-
die(DUMP_NOT_SUCCEEDED_WARNING)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
unlock_process
|
39
|
-
puts Kellerkind::Config.finished_dumping(mongo.db)
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.process_locked?
|
43
|
-
die(PROCESS_LOCKED_WARNING) if File.exists?(Kellerkind::Config.lock_path)
|
14
|
+
Kellerkind::Config.verbose_output = options.delete(:verbose)
|
15
|
+
handle_type(options)
|
44
16
|
end
|
45
17
|
|
46
18
|
private
|
47
19
|
|
48
|
-
def self.
|
49
|
-
|
20
|
+
def self.handle_type(options={})
|
21
|
+
module_name = options[:type].capitalize
|
22
|
+
Module.const_get("Kellerkind").const_get("#{module_name}").exec(options)
|
23
|
+
rescue NameError => name_error
|
24
|
+
raise name_error
|
25
|
+
die("No module named '#{module_name}' registered.")
|
50
26
|
end
|
51
27
|
|
52
|
-
def self.unlock_process
|
53
|
-
Kellerkind::Lock.unlock_process
|
54
|
-
end
|
55
28
|
end
|
56
|
-
end
|
29
|
+
end
|
data/spec/fixtures/mongodb.js
CHANGED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kellerkind::LogFile do
|
4
|
+
let(:out_dir) do
|
5
|
+
File.expand_path(File.join(File.dirname(__FILE__),"..", '..',"tmp"))
|
6
|
+
end
|
7
|
+
|
8
|
+
it { should respond_to(:files) }
|
9
|
+
it { should respond_to(:out) }
|
10
|
+
it { should respond_to(:recreate) }
|
11
|
+
|
12
|
+
|
13
|
+
describe "instance methods" do
|
14
|
+
|
15
|
+
let(:attributes) do
|
16
|
+
{
|
17
|
+
:files => ["$HOME/tmp/kellerkind.lock"],
|
18
|
+
:out => out_dir,
|
19
|
+
:recreate => true
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
it{ should respond_to(:archive) }
|
24
|
+
|
25
|
+
describe "#initialize" do
|
26
|
+
|
27
|
+
context "with a hash of attributes" do
|
28
|
+
|
29
|
+
context "that uses the proper prefix" do
|
30
|
+
|
31
|
+
subject{ Kellerkind::LogFile.new(attributes) }
|
32
|
+
|
33
|
+
it "then initializes the instance with the attribute values" do
|
34
|
+
subject.files.should eq attributes[:files]
|
35
|
+
subject.out.should eq attributes[:out]
|
36
|
+
subject.recreate.should eq attributes[:recreate]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#archive" do
|
45
|
+
let(:rel_path) do
|
46
|
+
path = File.join(__FILE__,'..','..','..','..','fixtures')
|
47
|
+
File.expand_path(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:sample_file){ "#{rel_path}/sample.log" }
|
51
|
+
|
52
|
+
before do
|
53
|
+
FileUtils.touch(sample_file)
|
54
|
+
attributes[:files] = [sample_file]
|
55
|
+
end
|
56
|
+
|
57
|
+
after do
|
58
|
+
Dir["#{out_dir}/*.tar.gz"].each{ |tar| FileUtils.rm(tar) }
|
59
|
+
if File.exist?(sample_file)
|
60
|
+
FileUtils.rm(sample_file)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context ":recreate given and true" do
|
65
|
+
|
66
|
+
subject{ Kellerkind::LogFile.new(attributes) }
|
67
|
+
|
68
|
+
it "moves and compresses the files" do
|
69
|
+
subject.archive
|
70
|
+
Dir["#{out_dir}/sample.log_*.tar.gz"].should have(1).item
|
71
|
+
end
|
72
|
+
|
73
|
+
it "files are newly created" do
|
74
|
+
File.exist?(sample_file).should be true
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context ":recreate given and false" do
|
79
|
+
|
80
|
+
before do
|
81
|
+
attributes[:recreate] = false
|
82
|
+
end
|
83
|
+
|
84
|
+
subject{ Kellerkind::LogFile.new(attributes) }
|
85
|
+
|
86
|
+
it "files are removed" do
|
87
|
+
subject.archive
|
88
|
+
File.exist?(sample_file).should be false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -118,7 +118,8 @@ describe Kellerkind::Mongo do
|
|
118
118
|
end
|
119
119
|
|
120
120
|
before do
|
121
|
-
|
121
|
+
rel_path = File.join(__FILE__,'..','..','..','..','fixtures')
|
122
|
+
js_path = File.expand_path(rel_path)
|
122
123
|
system("`which mongo` #{js_path}/mongodb.js")
|
123
124
|
end
|
124
125
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kellerkind::Mongodb do
|
4
|
+
|
5
|
+
describe "class methods" do
|
6
|
+
|
7
|
+
describe "#exec" do
|
8
|
+
|
9
|
+
let(:dbname){ "kellerkindTest"}
|
10
|
+
let(:out_dir) do
|
11
|
+
File.expand_path(File.join(File.dirname(__FILE__),"..", "tmp"))
|
12
|
+
end
|
13
|
+
before do
|
14
|
+
rel_path = File.join(__FILE__,'..','..','..','fixtures')
|
15
|
+
js_path = File.expand_path(rel_path)
|
16
|
+
system("`which mongo` #{js_path}/mongodb.js")
|
17
|
+
Kellerkind::Process.unlock
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
Dir["#{out_dir}/#{dbname}*.tar.gz"].each{ |tar| FileUtils.rm(tar) }
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:attributes) do
|
25
|
+
{
|
26
|
+
:mongo_db => dbname,
|
27
|
+
:mongo_host => "localhost",
|
28
|
+
:mongo_port => "27017",
|
29
|
+
:out => out_dir,
|
30
|
+
:remove_dump => true,
|
31
|
+
:compress => true
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "dumps a database" do
|
36
|
+
Kellerkind::Mongodb.exec(attributes)
|
37
|
+
Dir["#{out_dir}/#{dbname}_*.tar.gz"].should have(1).item
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -2,8 +2,9 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Kellerkind::Compress do
|
4
4
|
|
5
|
-
it{ should respond_to(:
|
6
|
-
it{ should respond_to(:
|
5
|
+
it{ should respond_to(:source_path) }
|
6
|
+
it{ should respond_to(:target_path) }
|
7
|
+
it{ should respond_to(:tarball_prefix)}
|
7
8
|
|
8
9
|
describe "instance methods" do
|
9
10
|
let(:out_dir) do
|
@@ -11,8 +12,8 @@ describe Kellerkind::Compress do
|
|
11
12
|
end
|
12
13
|
let(:attributes) do
|
13
14
|
{
|
14
|
-
:
|
15
|
-
:
|
15
|
+
:tarball_prefix => "test",
|
16
|
+
:target_path => out_dir
|
16
17
|
}
|
17
18
|
end
|
18
19
|
|
@@ -22,18 +23,20 @@ describe Kellerkind::Compress do
|
|
22
23
|
subject{ Kellerkind::Compress.new(attributes) }
|
23
24
|
|
24
25
|
it "then initializes the instance with the attributes values" do
|
25
|
-
subject.
|
26
|
-
subject.
|
26
|
+
subject.target_path.should eq attributes[:target_path]
|
27
|
+
subject.tarball_prefix.should eq attributes[:tarball_prefix]
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
31
|
describe "#gzip" do
|
31
32
|
let(:test_dump) do
|
32
|
-
File.join(out_dir,
|
33
|
+
File.join(out_dir, "kellerkindTest")
|
33
34
|
end
|
34
35
|
|
35
36
|
let(:compress) do
|
36
|
-
Kellerkind::Compress.new(:
|
37
|
+
Kellerkind::Compress.new(:target_path => out_dir,
|
38
|
+
:source_path => test_dump,
|
39
|
+
:tarball_prefix => "test")
|
37
40
|
end
|
38
41
|
|
39
42
|
before do
|
@@ -48,7 +51,7 @@ describe Kellerkind::Compress do
|
|
48
51
|
end
|
49
52
|
|
50
53
|
it "tars and gzip the given database dump" do
|
51
|
-
Dir["#{out_dir}/#{compress.
|
54
|
+
Dir["#{out_dir}/#{compress.tarball_prefix}_*.tar.gz"].should have(1).item
|
52
55
|
end
|
53
56
|
|
54
57
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kellerkind
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: virtus
|
@@ -134,8 +134,8 @@ extra_rdoc_files:
|
|
134
134
|
files:
|
135
135
|
- .document
|
136
136
|
- .rspec
|
137
|
+
- .travis.yml
|
137
138
|
- Gemfile
|
138
|
-
- Gemfile.lock
|
139
139
|
- LICENSE.txt
|
140
140
|
- README.md
|
141
141
|
- Rakefile
|
@@ -146,18 +146,24 @@ files:
|
|
146
146
|
- lib/kellerkind/core/configuration.rb
|
147
147
|
- lib/kellerkind/core/ext.rb
|
148
148
|
- lib/kellerkind/core/set.rb
|
149
|
-
- lib/kellerkind/database/mongo.rb
|
150
149
|
- lib/kellerkind/dependencies.rb
|
150
|
+
- lib/kellerkind/modules/implementations/log_file.rb
|
151
|
+
- lib/kellerkind/modules/implementations/mongo.rb
|
152
|
+
- lib/kellerkind/modules/log.rb
|
153
|
+
- lib/kellerkind/modules/modules.rb
|
154
|
+
- lib/kellerkind/modules/mongodb.rb
|
151
155
|
- lib/kellerkind/system/compress.rb
|
152
156
|
- lib/kellerkind/system/die.rb
|
153
157
|
- lib/kellerkind/system/lock.rb
|
158
|
+
- lib/kellerkind/system/process.rb
|
154
159
|
- lib/kellerkind/system/runner.rb
|
155
160
|
- spec/fixtures/mongodb.js
|
156
|
-
- spec/kellerkind/
|
161
|
+
- spec/kellerkind/modules/implementations/log_file_spec.rb
|
162
|
+
- spec/kellerkind/modules/implementations/mongo_spec.rb
|
163
|
+
- spec/kellerkind/modules/mongodb_spec.rb
|
157
164
|
- spec/kellerkind/system/compress_spec.rb
|
158
165
|
- spec/kellerkind/system/lock_spec.rb
|
159
166
|
- spec/kellerkind/tmp/.gitkeep
|
160
|
-
- spec/kellerkind_spec.rb
|
161
167
|
- spec/spec_helper.rb
|
162
168
|
homepage: http://github.com/dsci/kellerkind
|
163
169
|
licenses:
|
@@ -174,7 +180,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
174
180
|
version: '0'
|
175
181
|
segments:
|
176
182
|
- 0
|
177
|
-
hash:
|
183
|
+
hash: 2107316409361176975
|
178
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
185
|
none: false
|
180
186
|
requirements:
|
data/Gemfile.lock
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
addressable (2.3.5)
|
5
|
-
backports (3.3.3)
|
6
|
-
builder (3.2.2)
|
7
|
-
descendants_tracker (0.0.1)
|
8
|
-
diff-lcs (1.2.4)
|
9
|
-
faraday (0.8.7)
|
10
|
-
multipart-post (~> 1.1)
|
11
|
-
git (1.2.5)
|
12
|
-
github_api (0.10.1)
|
13
|
-
addressable
|
14
|
-
faraday (~> 0.8.1)
|
15
|
-
hashie (>= 1.2)
|
16
|
-
multi_json (~> 1.4)
|
17
|
-
nokogiri (~> 1.5.2)
|
18
|
-
oauth2
|
19
|
-
hashie (2.0.5)
|
20
|
-
highline (1.6.19)
|
21
|
-
httpauth (0.2.0)
|
22
|
-
jeweler (1.8.6)
|
23
|
-
builder
|
24
|
-
bundler (~> 1.0)
|
25
|
-
git (>= 1.2.5)
|
26
|
-
github_api (= 0.10.1)
|
27
|
-
highline (>= 1.6.15)
|
28
|
-
nokogiri (= 1.5.10)
|
29
|
-
rake
|
30
|
-
rdoc
|
31
|
-
json (1.8.0)
|
32
|
-
jwt (0.1.8)
|
33
|
-
multi_json (>= 1.5)
|
34
|
-
minitar (0.5.4)
|
35
|
-
multi_json (1.7.7)
|
36
|
-
multi_xml (0.5.4)
|
37
|
-
multipart-post (1.2.0)
|
38
|
-
nokogiri (1.5.10)
|
39
|
-
oauth2 (0.9.2)
|
40
|
-
faraday (~> 0.8)
|
41
|
-
httpauth (~> 0.2)
|
42
|
-
jwt (~> 0.1.4)
|
43
|
-
multi_json (~> 1.0)
|
44
|
-
multi_xml (~> 0.5)
|
45
|
-
rack (~> 1.2)
|
46
|
-
rack (1.5.2)
|
47
|
-
rake (10.1.0)
|
48
|
-
rdoc (3.12.2)
|
49
|
-
json (~> 1.4)
|
50
|
-
rspec (2.13.0)
|
51
|
-
rspec-core (~> 2.13.0)
|
52
|
-
rspec-expectations (~> 2.13.0)
|
53
|
-
rspec-mocks (~> 2.13.0)
|
54
|
-
rspec-core (2.13.1)
|
55
|
-
rspec-expectations (2.13.0)
|
56
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
57
|
-
rspec-mocks (2.13.1)
|
58
|
-
trollop (2.0)
|
59
|
-
virtus (0.5.5)
|
60
|
-
backports (~> 3.3)
|
61
|
-
descendants_tracker (~> 0.0.1)
|
62
|
-
|
63
|
-
PLATFORMS
|
64
|
-
ruby
|
65
|
-
|
66
|
-
DEPENDENCIES
|
67
|
-
bundler (~> 1.3.5)
|
68
|
-
jeweler (~> 1.8.4)
|
69
|
-
minitar (~> 0.5.4)
|
70
|
-
rdoc (~> 3.12)
|
71
|
-
rspec (~> 2.13.0)
|
72
|
-
trollop
|
73
|
-
virtus (~> 0.5.5)
|