backdat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,30 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "yajl-ruby", "~> 1.1.0"
7
+ gem "eventmachine", "~> 0.12.10"
8
+ gem "em-synchrony", "~> 0.2.0"
9
+ gem "redis", "~> 3.0.1"
10
+
11
+ gem "tilt", "~> 1.3.3"
12
+
13
+ gem "mixlib-cli", ">= 1.2.2"
14
+ gem "mixlib-config", ">= 1.1.0"
15
+ gem "mixlib-log", ">= 1.3.0"
16
+
17
+ gem "puma", "~> 1.5.0"
18
+ gem "rack", "~> 1.4.1"
19
+ gem "sinatra", "~> 1.3.2"
20
+
21
+ # Add dependencies to develop your gem here.
22
+ # Include everything needed to run rake, tests, features, etc.
23
+ group :development do
24
+ gem "rspec", "~> 2.10.0"
25
+ gem "yard", "~> 0.8"
26
+ gem "cucumber", ">= 0"
27
+ gem "bundler", "~> 1.1.0"
28
+ gem "jeweler", "~> 1.8.3"
29
+ gem (RUBY_VERSION =~ /^1\.9/ ? "simplecov" : "rcov"), ">= 0"
30
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Josh Toft
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # backdat
2
+
3
+ A better backup library and service.
4
+
5
+ ## Library
6
+
7
+ The library consists of a number of backends very similar to the backup gem.
8
+
9
+ ## Service
10
+
11
+ backdat manages backups for the current node and it's transports to the
12
+ various storage backends.
13
+
14
+ ## Orchestrator
15
+
16
+ Currently not implemented. Intended to acts as a proxy for multiple servers.
17
+
18
+ ## Contributing to backdat
19
+
20
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
21
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
22
+ * Fork the project.
23
+ * Start a feature/bugfix branch.
24
+ * Commit and push until you are happy with your contribution.
25
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
26
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
27
+
28
+ ## Copyright
29
+
30
+ Copyright (c) 2012 Josh Toft. See LICENSE.txt for
31
+ further details.
32
+
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
15
+ require 'jeweler'
16
+ require 'backdat'
17
+ Jeweler::Tasks.new do |gem|
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.name = "backdat"
20
+ gem.homepage = "http://github.com/seryl/backdat"
21
+ gem.license = "MIT"
22
+ gem.summary = %Q{A better backup library and service.}
23
+ gem.description = %Q{A better backup library and service.}
24
+ gem.email = "joshtoft@gmail.com"
25
+ gem.authors = ["Josh Toft"]
26
+ gem.version = Backdat::VERSION
27
+ # dependencies defined in Gemfile
28
+ end
29
+ Jeweler::RubygemsDotOrgTasks.new
30
+
31
+ require 'rspec/core'
32
+ require 'rspec/core/rake_task'
33
+ RSpec::Core::RakeTask.new(:spec) do |spec|
34
+ spec.pattern = FileList['spec/**/*_spec.rb']
35
+ end
36
+
37
+ if RUBY_VERSION =~ /^1\.9/
38
+ desc "Code coverage detail"
39
+ task :simplecov do
40
+ ENV['COVERAGE'] = "true"
41
+ Rake::Task['spec'].execute
42
+ end
43
+ else
44
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
45
+ spec.pattern = 'spec/**/*_spec.rb'
46
+ spec.rcov = true
47
+ end
48
+ end
49
+
50
+ require 'cucumber/rake/task'
51
+ Cucumber::Rake::Task.new(:features)
52
+
53
+ task :default => :spec
54
+
55
+ require 'yard'
56
+ YARD::Rake::YardocTask.new
data/bin/backdat ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'backdat'
5
+ require 'backdat/application/backdat-server'
6
+
7
+ Backdat::Application::Server.new.run
@@ -0,0 +1,9 @@
1
+ Feature: something something
2
+ In order to something something
3
+ A user something something
4
+ something something something
5
+
6
+ Scenario: something something
7
+ Given inspiration
8
+ When I create a sweet new gem
9
+ Then everyone should see how awesome I am
File without changes
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ begin
3
+ Bundler.setup(:default, :development)
4
+ rescue Bundler::BundlerError => e
5
+ $stderr.puts e.message
6
+ $stderr.puts "Run `bundle install` to install missing gems"
7
+ exit e.status_code
8
+ end
9
+
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
+ require 'backdat'
12
+
13
+ require 'rspec/expectations'
@@ -0,0 +1,119 @@
1
+ require 'backdat/application'
2
+ require 'backdat/client'
3
+ require 'backdat/server'
4
+
5
+ # The backdat server command line parser.
6
+ class Backdat::Application::Server < Backdat::Application
7
+
8
+ option :config_file,
9
+ :short => "-c CONFIG",
10
+ :long => "--config CONFIG",
11
+ :default => "/etc/backdat.rb",
12
+ :description => "The configuration file to use"
13
+
14
+ option :log_level,
15
+ :short => "-l LEVEL",
16
+ :long => "--log_level LEVEL",
17
+ :description => "Set the log level (debug, info, warn, error, fatal)",
18
+ :proc => lambda { |l| l.to_sym }
19
+
20
+ option :log_location,
21
+ :short => "-L LOG_LOCATION",
22
+ :long => "--logfile LOG_LOCATION",
23
+ :description => "Set the log file location, defaults to STDOUT",
24
+ :proc => nil
25
+
26
+ option :user,
27
+ :short => "-u USER",
28
+ :long => "--user USER",
29
+ :description => "User to set privilege to",
30
+ :proc => nil
31
+
32
+ option :group,
33
+ :short => "-g GROUP",
34
+ :long => "--group GROUP",
35
+ :description => "Group to set privilege to",
36
+ :proc => nil
37
+
38
+ option :daemonize,
39
+ :short => "-d",
40
+ :long => "--daemonize",
41
+ :default => false,
42
+ :description => "Run the application as a daemon (forces `-s`)",
43
+ :proc => lambda { |p| true }
44
+
45
+ option :environment,
46
+ :short => "-E",
47
+ :long => "--environment",
48
+ :description => "The environment profile to use",
49
+ :proc => nil
50
+
51
+ option :rack_host,
52
+ :short => "-H HOSTNAME",
53
+ :long => "--hostname HOSTNAME",
54
+ :description => "Hostname to listen on (default: 0.0.0.0)",
55
+ :proc => nil
56
+
57
+ option :rack_port,
58
+ :short => "-P PORT",
59
+ :long => "--port PORT",
60
+ :description => "Port to listen on (default: 8080)",
61
+ :proc => lambda { |p| p.to_i }
62
+
63
+ option :pid_file,
64
+ :short => "-f PID_FILE",
65
+ :long => "--pid PID_FILE",
66
+ :description => "Set the PID file location, defaults to /tmp/backdat.pid",
67
+ :proc => nil
68
+
69
+ option :server,
70
+ :short => "-s",
71
+ :long => "--server",
72
+ :default => false,
73
+ :description => "Start the application as a server",
74
+ :boolean => true,
75
+ :proc => nil
76
+
77
+ option :help,
78
+ :short => "-h",
79
+ :long => "--help",
80
+ :description => "Show this message",
81
+ :on => :tail,
82
+ :boolean => true,
83
+ :show_options => true,
84
+ :exit => 0
85
+
86
+ option :version,
87
+ :short => "-v",
88
+ :long => "--version",
89
+ :description => "Show backdat version",
90
+ :boolean => true,
91
+ :proc => lambda { |v| puts "backdat: #{::Backdat::VERSION}"},
92
+ :exit => 0
93
+
94
+ # Grabs all of the cli parameters and generates the mixlib config object.
95
+ def initialize
96
+ super
97
+ Backdat::Config.merge!(config)
98
+ end
99
+
100
+ # Configures the backdat server based on the cli parameters.
101
+ def setup_application
102
+ Backdat::Daemon.change_privilege
103
+ Backdat::Config[:server] = true if Backdat::Config[:daemonize]
104
+ if Backdat::Config[:server]
105
+ @app = Backdat::Server.new
106
+ else
107
+ @app = Backdat::Client.new(*ARGV)
108
+ end
109
+ end
110
+
111
+ # Runs the backdat server.
112
+ def run_application
113
+ if Backdat::Config[:daemonize]
114
+ Backdat::Config[:server] = true
115
+ Backdat::Daemon.daemonize("backdat")
116
+ end
117
+ @app.run
118
+ end
119
+ end
@@ -0,0 +1,134 @@
1
+ require 'mixlib/cli'
2
+
3
+ # The backdat application class for both server and worker.
4
+ class Backdat::Application
5
+ include Mixlib::CLI
6
+
7
+ # Added a Wakeup exception.
8
+ class Wakeup < Exception; end
9
+
10
+ # Initialize the application, setting up default handlers.
11
+ def initialize
12
+ super
13
+
14
+ trap("TERM") do
15
+ Backdat::Application.fatal!("SIGTERM received, stopping", 1)
16
+ end
17
+
18
+ trap("INT") do
19
+ Backdat::Application.fatal!("SIGINT received, stopping", 2)
20
+ end
21
+
22
+ trap("QUIT") do
23
+ Backdat::Log.info("SIGQUIT received, call stack:\n ", caller.join("\n "))
24
+ end
25
+
26
+ trap("HUP") do
27
+ Backdat::Log.info("SIGHUP received, reconfiguring")
28
+ reconfigure
29
+ end
30
+ end
31
+
32
+ # Reconfigure the application and logging.
33
+ def reconfigure
34
+ configure_backdat
35
+ configure_logging
36
+ end
37
+
38
+ # Configure the application throwing a warning when there is no config file.
39
+ def configure_backdat
40
+ parse_options
41
+
42
+ begin
43
+ ::File.open(config[:config_file]) { |f| apply_config(f.path) }
44
+ rescue Errno::ENOENT => error
45
+ msg = "Did not find the config file: #{config[:config_file]}"
46
+ msg << ", Using command line options."
47
+ Backdat::Log.warn "*****************************************"
48
+ Backdat::Log.warn msg
49
+ Backdat::Log.warn "*****************************************"
50
+ end
51
+ end
52
+
53
+ # Configures the logging in a relatively sane fashion.
54
+ # Only prints to STDOUT given a valid tty.
55
+ # Does not write to STDOUT when daemonizing.
56
+ def configure_logging
57
+ Backdat::Log.init(Backdat::Config[:log_location])
58
+ if ( Backdat::Config[:log_location] != STDOUT ) && STDOUT.tty? &&
59
+ ( !Backdat::Config[:daemonize] )
60
+ stdout_loger = Logger.new(STDOUT)
61
+ STDOUT.sync = true
62
+ stdout_logger = Backdat::Log.logger.formatter
63
+ Backdat::Log.loggers << stdout_logger
64
+ end
65
+ Backdat::Log.level = Backdat::Config[:log_level]
66
+ end
67
+
68
+ # Run the application itself. Configure, setup, and then run.
69
+ def run
70
+ reconfigure
71
+ setup_application
72
+ run_application
73
+ end
74
+
75
+ # Placeholder for setup_application, intended to be overridden.
76
+ #
77
+ # @raise Backdat::Exceptions::Application Must be overridden.
78
+ def setup_application
79
+ error_msg = "#{self.to_s}: you must override setup_application"
80
+ raise Backdat::Exceptions::Application, error_msg
81
+ end
82
+
83
+ # Placeholder for run_application, intended to be overridden.
84
+ #
85
+ # @raise Backdat::Exceptions::Application Must be overridden.
86
+ def run_application
87
+ error_msg = "#{self.to_s}: you must override run_application"
88
+ raise Backdat::Exceptions::Application, error_msg
89
+ end
90
+
91
+ private
92
+
93
+ # Apply the configuration given a file path.
94
+ #
95
+ # @param [ String ] config_file_path The path to the configuration file.
96
+ def apply_config(config_file_path)
97
+ Backdat::Config.from_file(config_file_path)
98
+ Backdat::Config.merge!(config)
99
+ end
100
+
101
+ class << self
102
+ # Present a debug stracktrace upon an error.
103
+ # Gives a readable backtrace with a timestamp.
104
+ #
105
+ # @param [ Exception ] e The raised exception.
106
+ def debug_stacktrace(e)
107
+ message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
108
+ stacktrace_out = "Generated at #{Time.now.to_s}\n"
109
+ stacktrace_out += message
110
+
111
+ Backdat::Log.debug(message)
112
+ end
113
+
114
+ # Log a fatal error message to both STDERR and the Logger,
115
+ # exit the application with a fatal message.
116
+ #
117
+ # @param [ String ] msg The message to log.
118
+ # @param [ Fixnum ] err The exit level.
119
+ def fatal!(msg, err = -1)
120
+ Backdat::Log.fatal(msg)
121
+ Process.exit err
122
+ end
123
+
124
+ # Log a fatal error message to both STDERR and the Logger,
125
+ # exit the application with a debug message.
126
+ #
127
+ # @param [ String ] msg The message to log.
128
+ # @param [ Fixnum ] err The exit level.
129
+ def exit!(msg, err = -1)
130
+ Backdat::Log.debug(msg)
131
+ Process.exit err
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,10 @@
1
+ # The backdat client application.
2
+ class Backdat::Client
3
+ def initialize(*argv)
4
+ p argv
5
+ end
6
+
7
+ def run
8
+ puts "running client"
9
+ end
10
+ end
@@ -0,0 +1,84 @@
1
+ require 'backdat/log'
2
+ require 'mixlib/config'
3
+ require 'yajl'
4
+
5
+ # The configuration object for backdat.
6
+ class Backdat::Config
7
+ extend Mixlib::Config
8
+
9
+ # Return the configuration itself upon inspection.
10
+ def self.inspect
11
+ configuration.inspect
12
+ end
13
+
14
+ # Loads a given file and passes it to the appropriate parser.
15
+ #
16
+ # @raise [ IOError ] Any IO Exceptions that occur.
17
+ #
18
+ # @param [ String ] filename The filename to read.
19
+ def self.from_file(filename, parser="ruby")
20
+ send("from_file_#{parser}".to_sym, filename)
21
+ end
22
+
23
+ # Loads a given ruby file and runs instance_eval against it
24
+ # in the context of the current object.
25
+ #
26
+ # @raise [ IOError ] Any IO Exceptions that occur.
27
+ #
28
+ # @param [ String ] filename The file to read.
29
+ def self.from_file_ruby(filename)
30
+ self.instance_eval(IO.read(filename), filename, 1)
31
+ end
32
+
33
+ # Loads a given json file and merges the current context
34
+ # configuration with the updated hash.
35
+ #
36
+ # @raise [ IOError ] Any IO Exceptions that occur.
37
+ # @raise [ Yajl::ParseError ] Raises Yajl Parsing error on improper json.
38
+ #
39
+ # @param [ String ] filename The file to read.
40
+ def self.from_file_json(filename)
41
+ self.from_stream_json(IO.read(filename))
42
+ end
43
+
44
+ # Loads a given json input and merges the current context
45
+ # configuration with the updated hash.
46
+ #
47
+ # @raise [ IOError ] Any IO Exceptions that occur.
48
+ # @raise [ Yajl::ParseError ] Raises Yajl Parsing error on improper json.
49
+ #
50
+ # @param [ String ] input The json configuration input.
51
+ def self.from_stream_json(input)
52
+ parser = Yajl::Parser.new(:symbolize_keys => true)
53
+ configuration.merge!(parser.parse(input))
54
+ end
55
+
56
+ # When you are using ActiveSupport, they monkey-patch 'daemonize' into
57
+ # Kernel. So while this is basically identical to what method_missing
58
+ # would do, we pull it up here and get a real method written so that
59
+ # things get dispatched properly.
60
+ config_attr_writer :daemonize do |v|
61
+ configure do |c|
62
+ c[:daemonize] = v
63
+ end
64
+ end
65
+
66
+ # Configuration Settings
67
+ config_file "/etc/backdat.rb"
68
+
69
+ # Logging Settings
70
+ log_level :info
71
+ log_location STDOUT
72
+
73
+ # Daemonization Settings
74
+ user nil
75
+ group nil
76
+ umask 0022
77
+
78
+ pid_file nil
79
+
80
+ # Rack Settings
81
+ rack_host "0.0.0.0"
82
+ rack_port 8080
83
+ rack_environment "development"
84
+ end
@@ -0,0 +1,155 @@
1
+ require 'etc'
2
+
3
+ # Daemon helper routines.
4
+ class Backdat::Daemon
5
+ class << self
6
+ attr_accessor :name
7
+
8
+ # Daemonize the current process, managing pidfiles and process uid/gid.
9
+ #
10
+ # @param [ String ] name The name to be used for the pid file
11
+ def daemonize(name)
12
+ @name = name
13
+ pid = pid_from_file
14
+ unless running?
15
+ remove_pid_file()
16
+ Backdat::Log.info("Daemonizing...")
17
+ begin
18
+ exit if fork; Process.setsid; exit if fork
19
+ msg = "Forked, in #{Process.pid}. "
20
+ msg << "Privileges: #{Process.euid} #{Process.egid}"
21
+ Backdat::Log.info(msg)
22
+ File.umask Backdat::Config[:umask]
23
+ $stdin.reopen("/dev/null")
24
+ $stdout.reopen("/dev/null", "a")
25
+ $stderr.reopen($stdout)
26
+ save_pid_file;
27
+ at_exit { remove_pid_file }
28
+ rescue NotImplementedError => e
29
+ Backdat::Application.fatal!("There is no fork: #{e.message}")
30
+ end
31
+ else
32
+ Backdat::Application.fatal!("Backdat is already running pid #{pid}")
33
+ end
34
+ end
35
+
36
+ # Checks if Backdat is running based on the pid_file.
37
+ #
38
+ # @return [ true,false ] Whether or not Backdat is running.
39
+ def running?
40
+ if pid_from_file.nil?
41
+ false
42
+ else
43
+ Process.kill(0, pid_from_file)
44
+ true
45
+ end
46
+ rescue Errno::ESRCH, Errno::ENOENT
47
+ false
48
+ rescue Errno::EACCES => e
49
+ msg = "You don't have access to the PID "
50
+ msg << "file at #{pid_file}: #{e.message}"
51
+ Backdat::Application.fatal!(msg)
52
+ end
53
+
54
+ # Gets the pid file for @name.
55
+ #
56
+ # @return [ String ] Location of the pid file for @name.
57
+ def pid_file
58
+ Backdat::Config[:pid_file] or "/tmp/#{@name}.pid"
59
+ end
60
+
61
+ # Sucks the pid out of pid_file.
62
+ #
63
+ # @return [ Fixnum,NilClass ] The PID from pid_file or nil if it doesn't exist.
64
+ def pid_from_file
65
+ File.read(pid_file).chomp.to_i
66
+ rescue Errno::ENOENT, Errno::EACCES
67
+ nil
68
+ end
69
+
70
+ # Store the PID on the filesystem.
71
+ #
72
+ # @note
73
+ # This uses the Backdat::Config[:pid_file] option or "/tmp/name.pid"
74
+ # by default.
75
+ def save_pid_file
76
+ file = pid_file
77
+ begin
78
+ FileUtils.mkdir_p(File.dirname(file))
79
+ rescue Errno::EACCES => e
80
+ msg = "Failed store pid in #{File.dirname(file)}, "
81
+ msg << "permission denied: #{e.message}"
82
+ Backdat::Application.fatal!(msg)
83
+ end
84
+
85
+ begin
86
+ File.open(file, "w") { |f| f.write(Process.pid.to_s) }
87
+ rescue Errno::EACCES => e
88
+ msg = "Couldn't write to pidfile #{file}, "
89
+ msg << "permission denied: #{e.message}"
90
+ Backdat::Application.fatal!(msg)
91
+ end
92
+ end
93
+
94
+ # Delete the PID from the filesystem
95
+ def remove_pid_file
96
+ FileUtils.rm(pid_file) if File.exists?(pid_file)
97
+ end
98
+
99
+ # Change process user/group to those specified in Backdat::Config
100
+ def change_privilege
101
+ Dir.chdir("/")
102
+
103
+ msg = "About to change privilege to "
104
+ if Backdat::Config[:user] and Backdat::Config[:group]
105
+ msg << "#{Backdat::Config[:user]}:#{Backdat::Config[:group]}"
106
+ Backdat::Log.info(msg)
107
+ _change_privilege(Backdat::Config[:user], Backdat::Config[:group])
108
+ elsif Backdat::Config[:user]
109
+ msg << "#{Backdat::Config[:user]}"
110
+ Backdat::Log.info(msg)
111
+ _change_privilege(Backdat::Config[:user])
112
+ end
113
+ end
114
+
115
+ # Change privileges of the process to be the specified user and group
116
+ #
117
+ # @param [ String ] user The user to change the process to.
118
+ # @param [ String ] group The group to change the process to.
119
+ #
120
+ # @note
121
+ # The group parameter defaults to user unless specified.
122
+ def _change_privilege(user, group=user)
123
+ uid, gid = Process.euid, Process.egid
124
+
125
+ begin
126
+ target_uid = Etc.getpwnam(user).uid
127
+ rescue ArgumentError => e
128
+ msg = "Failed to get UID for user #{user}, does it exist? "
129
+ msg << e.message
130
+ Backdat::Application.fatal!(msg)
131
+ return false
132
+ end
133
+
134
+ begin
135
+ target_gid = Etc.getgrnam(group).gid
136
+ rescue ArgumentError => e
137
+ msg = "Failed to get GID for group #{group}, does it exist? "
138
+ msg << e.message
139
+ Backdat::Application.fatal!(msg)
140
+ return false
141
+ end
142
+
143
+ if (uid != target_uid) or (gid != target_gid)
144
+ Process.initgroups(user, target_gid)
145
+ Process::GID.change_privilege(target_gid)
146
+ Process::UID.change_privilege(target_uid)
147
+ end
148
+ true
149
+ rescue Errno::EPERM => e
150
+ msg = "Permission denied when trying to change #{uid}:#{gid} "
151
+ msg << "to #{target_uid}:#{target_gid}. #{e.message}"
152
+ Backdat::Application.fatal!(msg)
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,8 @@
1
+ # The backdat exception list.
2
+ module Backdat::Exceptions
3
+ # Access is denied to the requested resource.
4
+ class AccessDenied < RuntimeError; end
5
+
6
+ # Erroenous HTTP response from a request.
7
+ class HTTPError < RuntimeError; end
8
+ end
@@ -0,0 +1,9 @@
1
+ require 'sinatra/base'
2
+
3
+ # The sinatra
4
+ class Backdat::Http < Sinatra::Base
5
+
6
+ get '/' do
7
+ "Hello world"
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ require 'logger'
2
+ require 'mixlib/log'
3
+
4
+ # Backdat's internal logging facility.
5
+ # Standardized to provide a consistent log format.
6
+ class Backdat::Log
7
+ extend Mixlib::Log
8
+
9
+ # Force initialization of the primary log device (@logger)
10
+ init
11
+
12
+ # Monkeypatch Formatter to allow local show_time updates.
13
+ class Formatter
14
+ # Allow enabling and disabling of time with a singleton.
15
+ def self.show_time=(*args)
16
+ Mixlib::Log::Formatter.show_time = *args
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ require 'puma'
2
+ require 'eventmachine'
3
+ require 'backdat/http'
4
+
5
+ # The backdat server and management daemon.
6
+ class Backdat::Server
7
+
8
+ # Creates a new backdat server.
9
+ def initialize
10
+ end
11
+
12
+ # Runs the server.
13
+ def run
14
+ if Backdat::Config[:server]
15
+ EM.run do
16
+ @app = Rack::Builder.new do
17
+ use Rack::Lint
18
+ use Rack::ShowExceptions
19
+ run Rack::Cascade.new([Backdat::Http])
20
+ end.to_app
21
+
22
+ Rack::Handler.get(:puma).run(@app, rack_options)
23
+ end
24
+ end
25
+ end
26
+
27
+ # Gets the rack options from the configuration.
28
+ #
29
+ # @return [ Hash ] The rack options from Backdat::Config.
30
+ def rack_options
31
+ opts = Hash.new
32
+ Backdat::Config.configuration.each do |k,v|
33
+ if /^rack/ =~ k.to_s
34
+ param = k.to_s.gsub('rack_', '')
35
+
36
+ case param
37
+ when "environment"
38
+ opts[param.to_sym] = v
39
+ else
40
+ opts[param.capitalize.to_sym] = v
41
+ end
42
+ end
43
+ end
44
+ opts
45
+ end
46
+
47
+ end
@@ -0,0 +1,5 @@
1
+ # A better backup library and service.
2
+ module Backdat
3
+ # The current backdat version.
4
+ VERSION = "0.0.1"
5
+ end
data/lib/backdat.rb ADDED
@@ -0,0 +1,8 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'backdat/version'
4
+ require 'backdat/log'
5
+ require 'backdat/exceptions'
6
+ require 'backdat/config'
7
+ require 'backdat/daemon'
8
+ require 'backdat/client'
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Backdat" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,32 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ if RUBY_VERSION =~ /^1\.9/
5
+ require 'simplecov'
6
+
7
+ module SimpleCov::Configuration
8
+ def clean_filters
9
+ @filters = []
10
+ end
11
+ end
12
+
13
+ SimpleCov.configure do
14
+ clean_filters
15
+ load_adapter 'test_frameworks'
16
+ end
17
+
18
+ ENV["COVERAGE"] && SimpleCov.start do
19
+ add_filter "/.rvm/"
20
+ end
21
+ end
22
+
23
+ require 'rspec'
24
+ require 'backdat'
25
+
26
+ # Requires supporting files with custom matchers and macros, etc,
27
+ # in ./support/ and its subdirectories.
28
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
29
+
30
+ RSpec.configure do |config|
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,344 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: backdat
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Josh Toft
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: yajl-ruby
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.1.0
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.1.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: eventmachine
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.12.10
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.12.10
46
+ - !ruby/object:Gem::Dependency
47
+ name: em-synchrony
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.2.0
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.0
62
+ - !ruby/object:Gem::Dependency
63
+ name: redis
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 3.0.1
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 3.0.1
78
+ - !ruby/object:Gem::Dependency
79
+ name: tilt
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 1.3.3
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.3.3
94
+ - !ruby/object:Gem::Dependency
95
+ name: mixlib-cli
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 1.2.2
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 1.2.2
110
+ - !ruby/object:Gem::Dependency
111
+ name: mixlib-config
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.1.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 1.1.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: mixlib-log
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: 1.3.0
134
+ type: :runtime
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: 1.3.0
142
+ - !ruby/object:Gem::Dependency
143
+ name: puma
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ~>
148
+ - !ruby/object:Gem::Version
149
+ version: 1.5.0
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ version: 1.5.0
158
+ - !ruby/object:Gem::Dependency
159
+ name: rack
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ~>
164
+ - !ruby/object:Gem::Version
165
+ version: 1.4.1
166
+ type: :runtime
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ~>
172
+ - !ruby/object:Gem::Version
173
+ version: 1.4.1
174
+ - !ruby/object:Gem::Dependency
175
+ name: sinatra
176
+ requirement: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ~>
180
+ - !ruby/object:Gem::Version
181
+ version: 1.3.2
182
+ type: :runtime
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ none: false
186
+ requirements:
187
+ - - ~>
188
+ - !ruby/object:Gem::Version
189
+ version: 1.3.2
190
+ - !ruby/object:Gem::Dependency
191
+ name: rspec
192
+ requirement: !ruby/object:Gem::Requirement
193
+ none: false
194
+ requirements:
195
+ - - ~>
196
+ - !ruby/object:Gem::Version
197
+ version: 2.10.0
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ none: false
202
+ requirements:
203
+ - - ~>
204
+ - !ruby/object:Gem::Version
205
+ version: 2.10.0
206
+ - !ruby/object:Gem::Dependency
207
+ name: yard
208
+ requirement: !ruby/object:Gem::Requirement
209
+ none: false
210
+ requirements:
211
+ - - ~>
212
+ - !ruby/object:Gem::Version
213
+ version: '0.8'
214
+ type: :development
215
+ prerelease: false
216
+ version_requirements: !ruby/object:Gem::Requirement
217
+ none: false
218
+ requirements:
219
+ - - ~>
220
+ - !ruby/object:Gem::Version
221
+ version: '0.8'
222
+ - !ruby/object:Gem::Dependency
223
+ name: cucumber
224
+ requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ - !ruby/object:Gem::Dependency
239
+ name: bundler
240
+ requirement: !ruby/object:Gem::Requirement
241
+ none: false
242
+ requirements:
243
+ - - ~>
244
+ - !ruby/object:Gem::Version
245
+ version: 1.1.0
246
+ type: :development
247
+ prerelease: false
248
+ version_requirements: !ruby/object:Gem::Requirement
249
+ none: false
250
+ requirements:
251
+ - - ~>
252
+ - !ruby/object:Gem::Version
253
+ version: 1.1.0
254
+ - !ruby/object:Gem::Dependency
255
+ name: jeweler
256
+ requirement: !ruby/object:Gem::Requirement
257
+ none: false
258
+ requirements:
259
+ - - ~>
260
+ - !ruby/object:Gem::Version
261
+ version: 1.8.3
262
+ type: :development
263
+ prerelease: false
264
+ version_requirements: !ruby/object:Gem::Requirement
265
+ none: false
266
+ requirements:
267
+ - - ~>
268
+ - !ruby/object:Gem::Version
269
+ version: 1.8.3
270
+ - !ruby/object:Gem::Dependency
271
+ name: simplecov
272
+ requirement: !ruby/object:Gem::Requirement
273
+ none: false
274
+ requirements:
275
+ - - ! '>='
276
+ - !ruby/object:Gem::Version
277
+ version: '0'
278
+ type: :development
279
+ prerelease: false
280
+ version_requirements: !ruby/object:Gem::Requirement
281
+ none: false
282
+ requirements:
283
+ - - ! '>='
284
+ - !ruby/object:Gem::Version
285
+ version: '0'
286
+ description: A better backup library and service.
287
+ email: joshtoft@gmail.com
288
+ executables:
289
+ - backdat
290
+ extensions: []
291
+ extra_rdoc_files:
292
+ - LICENSE.txt
293
+ - README.md
294
+ files:
295
+ - .document
296
+ - .rspec
297
+ - Gemfile
298
+ - LICENSE.txt
299
+ - README.md
300
+ - Rakefile
301
+ - bin/backdat
302
+ - features/backdat.feature
303
+ - features/step_definitions/backdat_steps.rb
304
+ - features/support/env.rb
305
+ - lib/backdat.rb
306
+ - lib/backdat/application.rb
307
+ - lib/backdat/application/backdat-server.rb
308
+ - lib/backdat/client.rb
309
+ - lib/backdat/config.rb
310
+ - lib/backdat/daemon.rb
311
+ - lib/backdat/exceptions.rb
312
+ - lib/backdat/http.rb
313
+ - lib/backdat/log.rb
314
+ - lib/backdat/server.rb
315
+ - lib/backdat/version.rb
316
+ - spec/backdat_spec.rb
317
+ - spec/spec_helper.rb
318
+ homepage: http://github.com/seryl/backdat
319
+ licenses:
320
+ - MIT
321
+ post_install_message:
322
+ rdoc_options: []
323
+ require_paths:
324
+ - lib
325
+ required_ruby_version: !ruby/object:Gem::Requirement
326
+ none: false
327
+ requirements:
328
+ - - ! '>='
329
+ - !ruby/object:Gem::Version
330
+ version: '0'
331
+ required_rubygems_version: !ruby/object:Gem::Requirement
332
+ none: false
333
+ requirements:
334
+ - - ! '>='
335
+ - !ruby/object:Gem::Version
336
+ version: '0'
337
+ requirements: []
338
+ rubyforge_project:
339
+ rubygems_version: 1.8.24
340
+ signing_key:
341
+ specification_version: 3
342
+ summary: A better backup library and service.
343
+ test_files: []
344
+ has_rdoc: