souffle 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -3
- data/README.md +6 -0
- data/bin/{souffle-server → souffle} +0 -0
- data/lib/souffle.rb +8 -8
- data/lib/souffle/application.rb +15 -10
- data/lib/souffle/application/souffle-server.rb +90 -5
- data/lib/souffle/config.rb +88 -59
- data/lib/souffle/daemon.rb +156 -0
- data/lib/souffle/exceptions.rb +29 -17
- data/lib/souffle/http.rb +43 -0
- data/lib/souffle/log.rb +11 -14
- data/lib/souffle/node.rb +91 -53
- data/lib/souffle/node/runlist.rb +16 -18
- data/lib/souffle/node/runlist_item.rb +43 -36
- data/lib/souffle/node/runlist_parser.rb +60 -62
- data/lib/souffle/polling_event.rb +110 -0
- data/lib/souffle/provider.rb +231 -23
- data/lib/souffle/provider/aws.rb +654 -7
- data/lib/souffle/provider/vagrant.rb +42 -5
- data/lib/souffle/provisioner.rb +55 -0
- data/lib/souffle/provisioner/node.rb +157 -0
- data/lib/souffle/provisioner/system.rb +195 -0
- data/lib/souffle/redis_client.rb +8 -0
- data/lib/souffle/redis_mixin.rb +40 -0
- data/lib/souffle/server.rb +42 -8
- data/lib/souffle/ssh_monkey.rb +8 -0
- data/lib/souffle/state.rb +16 -0
- data/lib/souffle/system.rb +139 -37
- data/lib/souffle/template.rb +30 -0
- data/lib/souffle/templates/Vagrantfile.erb +41 -0
- data/lib/souffle/version.rb +6 -0
- data/spec/config_spec.rb +20 -0
- data/spec/log_spec.rb +24 -0
- data/spec/{runlist_parser_spec.rb → node/runlist_parser_spec.rb} +1 -1
- data/spec/{runlist_spec.rb → node/runlist_spec.rb} +1 -1
- data/spec/node_spec.rb +43 -8
- data/spec/provider_spec.rb +56 -0
- data/spec/providers/aws_provider_spec.rb +114 -0
- data/spec/providers/vagrant_provider_spec.rb +22 -0
- data/spec/provisioner_spec.rb +47 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/system_spec.rb +242 -13
- data/spec/template_spec.rb +20 -0
- data/spec/templates/example_template.erb +1 -0
- metadata +125 -30
- data/bin/souffle-worker +0 -7
- data/lib/souffle/application/souffle-worker.rb +0 -46
- data/lib/souffle/providers.rb +0 -2
- data/lib/souffle/worker.rb +0 -14
data/Gemfile
CHANGED
@@ -7,21 +7,27 @@ gem "yajl-ruby", "~> 1.1.0"
|
|
7
7
|
gem "eventmachine", "~> 0.12.10"
|
8
8
|
gem "amqp", "~> 0.9.7"
|
9
9
|
gem "state_machine", "~> 1.1.2"
|
10
|
+
gem "em-ssh", "~> 0.4.0"
|
11
|
+
gem "em-synchrony", "~> 0.2.0"
|
10
12
|
|
11
13
|
gem "right_aws", "~> 3.0.4"
|
14
|
+
gem "tilt", "~> 1.3.3"
|
15
|
+
gem "redis", "~> 3.0.1"
|
12
16
|
|
13
|
-
gem "mixlib-cli"
|
17
|
+
gem "mixlib-cli", ">= 1.2.2"
|
14
18
|
gem "mixlib-config", ">= 1.1.0"
|
15
19
|
gem "mixlib-log", ">= 1.3.0"
|
16
20
|
|
21
|
+
gem "thin", "~> 1.4.1"
|
22
|
+
gem "rack", "~> 1.4.1"
|
23
|
+
gem "sinatra", "~> 1.3.2"
|
24
|
+
|
17
25
|
# Add dependencies to develop your gem here.
|
18
26
|
# Include everything needed to run rake, tests, features, etc.
|
19
27
|
group :development do
|
20
28
|
gem "rspec", "~> 2.10.0"
|
21
|
-
gem "fakefs", "~> 0.4.0"
|
22
29
|
gem "yard", "~> 0.8"
|
23
30
|
gem "redcarpet", "~> 2.1.1"
|
24
|
-
gem "rdoc", "~> 3.12"
|
25
31
|
gem "cucumber", ">= 0"
|
26
32
|
gem "bundler", "~> 1.1.0"
|
27
33
|
gem "jeweler", "~> 1.8.3"
|
data/README.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
An orchestrator for setting up isolated chef-managed systems.
|
4
4
|
|
5
|
+
## A note on tests
|
6
|
+
|
7
|
+
In order to avoid painfully silly charges and costs, all of the AWS tests
|
8
|
+
that require you to pay (spinning up machines, etc), will only run if you
|
9
|
+
have the environment variable `AWS_LIVE` set to `true`.
|
10
|
+
|
5
11
|
## Contributing to souffle
|
6
12
|
|
7
13
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
File without changes
|
data/lib/souffle.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__)
|
2
2
|
require 'yajl'
|
3
|
+
require 'yajl/json_gem'
|
3
4
|
require 'eventmachine'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
|
7
|
-
# An orchestrator for setting up isolated chef-managed systems.
|
8
|
-
module Souffle
|
9
|
-
VERSION = "0.0.1"
|
10
|
-
end
|
5
|
+
require 'em-ssh'
|
6
|
+
require 'em-synchrony'
|
11
7
|
|
8
|
+
require 'souffle/version'
|
9
|
+
require 'souffle/ssh_monkey'
|
12
10
|
require 'souffle/log'
|
13
11
|
require 'souffle/exceptions'
|
14
12
|
require 'souffle/config'
|
15
|
-
require 'souffle/
|
13
|
+
require 'souffle/daemon'
|
16
14
|
require 'souffle/node'
|
17
15
|
require 'souffle/system'
|
16
|
+
require 'souffle/provider'
|
17
|
+
require 'souffle/provisioner'
|
data/lib/souffle/application.rb
CHANGED
@@ -4,11 +4,15 @@ require 'mixlib/cli'
|
|
4
4
|
class Souffle::Application
|
5
5
|
include Mixlib::CLI
|
6
6
|
|
7
|
+
# The commands that were left unparsed from parse_options.
|
8
|
+
attr_accessor :commands
|
9
|
+
|
7
10
|
# Added a Wakeup exception.
|
8
11
|
class Wakeup < Exception; end
|
9
12
|
|
10
13
|
# Initialize the application, setting up default handlers.
|
11
14
|
def initialize
|
15
|
+
@commands = []
|
12
16
|
super
|
13
17
|
|
14
18
|
trap("TERM") do
|
@@ -42,10 +46,11 @@ class Souffle::Application
|
|
42
46
|
begin
|
43
47
|
::File.open(config[:config_file]) { |f| apply_config(f.path) }
|
44
48
|
rescue Errno::ENOENT => error
|
45
|
-
|
46
|
-
|
47
|
-
Souffle::Log.warn
|
48
|
-
Souffle::Log.warn
|
49
|
+
msg = "Did not find the config file: #{config[:config_file]}"
|
50
|
+
msg << ", Using command line options."
|
51
|
+
Souffle::Log.warn "*****************************************"
|
52
|
+
Souffle::Log.warn msg
|
53
|
+
Souffle::Log.warn "*****************************************"
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
@@ -56,9 +61,9 @@ class Souffle::Application
|
|
56
61
|
Souffle::Log.init(Souffle::Config[:log_location])
|
57
62
|
if ( Souffle::Config[:log_location] != STDOUT ) && STDOUT.tty? &&
|
58
63
|
( !Souffle::Config[:daemonize] )
|
59
|
-
|
64
|
+
stdout_logger = Logger.new(STDOUT)
|
60
65
|
STDOUT.sync = true
|
61
|
-
stdout_logger = Souffle::Log.logger.formatter
|
66
|
+
stdout_logger.formatter = Souffle::Log.logger.formatter
|
62
67
|
Souffle::Log.loggers << stdout_logger
|
63
68
|
end
|
64
69
|
Souffle::Log.level = Souffle::Config[:log_level]
|
@@ -113,8 +118,8 @@ class Souffle::Application
|
|
113
118
|
# Log a fatal error message to both STDERR and the Logger,
|
114
119
|
# exit the application with a fatal message.
|
115
120
|
#
|
116
|
-
# @param [
|
117
|
-
# @param [
|
121
|
+
# @param [ String ] msg The message to log.
|
122
|
+
# @param [ Fixnum ] err The exit level.
|
118
123
|
def fatal!(msg, err = -1)
|
119
124
|
Souffle::Log.fatal(msg)
|
120
125
|
Process.exit err
|
@@ -123,8 +128,8 @@ class Souffle::Application
|
|
123
128
|
# Log a fatal error message to both STDERR and the Logger,
|
124
129
|
# exit the application with a debug message.
|
125
130
|
#
|
126
|
-
# @param [
|
127
|
-
# @param [
|
131
|
+
# @param [ String ] msg The message to log.
|
132
|
+
# @param [ Fixnum ] err The exit level.
|
128
133
|
def exit!(msg, err = -1)
|
129
134
|
Souffle::Log.debug(msg)
|
130
135
|
Process.exit err
|
@@ -7,7 +7,7 @@ class Souffle::Application::Server < Souffle::Application
|
|
7
7
|
option :config_file,
|
8
8
|
:short => "-c CONFIG",
|
9
9
|
:long => "--config CONFIG",
|
10
|
-
:default => "/etc/souffle/
|
10
|
+
:default => "/etc/souffle/souffle.rb",
|
11
11
|
:description => "The configuration file to use"
|
12
12
|
|
13
13
|
option :log_level,
|
@@ -17,10 +17,78 @@ class Souffle::Application::Server < Souffle::Application
|
|
17
17
|
:proc => lambda { |l| l.to_sym }
|
18
18
|
|
19
19
|
option :log_location,
|
20
|
-
:short
|
21
|
-
:long
|
22
|
-
:description
|
23
|
-
:proc
|
20
|
+
:short => "-L LOG_LOCATION",
|
21
|
+
:long => "--logfile LOG_LOCATION",
|
22
|
+
:description => "Set the log file location, defaults to STDOUT",
|
23
|
+
:proc => nil
|
24
|
+
|
25
|
+
option :user,
|
26
|
+
:short => "-u USER",
|
27
|
+
:long => "--user USER",
|
28
|
+
:description => "User to set privilege to",
|
29
|
+
:proc => nil
|
30
|
+
|
31
|
+
option :group,
|
32
|
+
:short => "-g GROUP",
|
33
|
+
:long => "--group GROUP",
|
34
|
+
:description => "Group to set privilege to",
|
35
|
+
:proc => nil
|
36
|
+
|
37
|
+
option :daemonize,
|
38
|
+
:short => "-d",
|
39
|
+
:long => "--daemonize",
|
40
|
+
:default => false,
|
41
|
+
:description => "Run the application as a daemon (forces `-s`)",
|
42
|
+
:proc => lambda { |p| true }
|
43
|
+
|
44
|
+
option :environment,
|
45
|
+
:short => "-E",
|
46
|
+
:long => "--environment",
|
47
|
+
:description => "The environment profile to use",
|
48
|
+
:proc => nil
|
49
|
+
|
50
|
+
option :rack_host,
|
51
|
+
:short => "-H HOSTNAME",
|
52
|
+
:long => "--hostname HOSTNAME",
|
53
|
+
:description => "Hostname to listen on (default: 0.0.0.0)",
|
54
|
+
:proc => nil
|
55
|
+
|
56
|
+
option :rack_port,
|
57
|
+
:short => "-P PORT",
|
58
|
+
:long => "--port PORT",
|
59
|
+
:description => "Port to listen on (default: 8080)",
|
60
|
+
:proc => lambda { |p| p.to_i }
|
61
|
+
|
62
|
+
option :vagrant_dir,
|
63
|
+
:short => "-V VAGRANT_DIR",
|
64
|
+
:long => "--vagrant_dir VAGRANT_DIR",
|
65
|
+
:description => "The path to the base vagrant vm directory",
|
66
|
+
:proc => nil
|
67
|
+
|
68
|
+
option :pid_file,
|
69
|
+
:short => "-f PID_FILE",
|
70
|
+
:long => "--pid PID_FILE",
|
71
|
+
:description => "Set the PID file location, defaults to /tmp/souffle.pid",
|
72
|
+
:proc => nil
|
73
|
+
|
74
|
+
option :provider,
|
75
|
+
:short => "-p PROVIDER",
|
76
|
+
:long => "--provider PROVIDER",
|
77
|
+
:description => "The provider to use (overrides config)",
|
78
|
+
:proc => nil
|
79
|
+
|
80
|
+
option :json,
|
81
|
+
:short => "-j JSON",
|
82
|
+
:long => "--json JSON",
|
83
|
+
:description => "The json for a single provision (negates `-s`)",
|
84
|
+
:proc => nil
|
85
|
+
|
86
|
+
option :server,
|
87
|
+
:short => "-s",
|
88
|
+
:long => "--server",
|
89
|
+
:default => false,
|
90
|
+
:description => "Start the application as a server",
|
91
|
+
:proc => nil
|
24
92
|
|
25
93
|
option :help,
|
26
94
|
:short => "-h",
|
@@ -39,8 +107,25 @@ class Souffle::Application::Server < Souffle::Application
|
|
39
107
|
:proc => lambda { |v| puts "Souffle: #{::Souffle::VERSION}"},
|
40
108
|
:exit => 0
|
41
109
|
|
110
|
+
# Grabs all of the cli parameters and generates the mixlib config object.
|
42
111
|
def initialize
|
43
112
|
super
|
113
|
+
Souffle::Config.merge!(config)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Configures the souffle server based on the cli parameters.
|
117
|
+
def setup_application
|
118
|
+
Souffle::Daemon.change_privilege
|
119
|
+
Souffle::Config[:server] = true if Souffle::Config[:daemonize]
|
120
|
+
@app = Souffle::Server.new
|
121
|
+
end
|
44
122
|
|
123
|
+
# Runs the Souffle Server.
|
124
|
+
def run_application
|
125
|
+
if Souffle::Config[:daemonize]
|
126
|
+
Souffle::Config[:server] = true
|
127
|
+
Souffle::Daemon.daemonize("souffle")
|
128
|
+
end
|
129
|
+
@app.run
|
45
130
|
end
|
46
131
|
end
|
data/lib/souffle/config.rb
CHANGED
@@ -2,74 +2,103 @@ require 'souffle/log'
|
|
2
2
|
require 'mixlib/config'
|
3
3
|
require 'yajl'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# The configuration object for the souffle server.
|
6
|
+
class Souffle::Config
|
7
|
+
extend Mixlib::Config
|
8
8
|
|
9
|
-
|
9
|
+
# Return the configuration itself upon inspection.
|
10
|
+
def self.inspect
|
11
|
+
configuration.inspect
|
12
|
+
end
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
24
32
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
34
43
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
def self.from_stream_json(input)
|
54
|
-
parser = Yajl::Parser.new
|
55
|
-
configuration.merge!(parser.parse(input))
|
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
|
56
63
|
end
|
64
|
+
end
|
57
65
|
|
58
|
-
|
59
|
-
|
60
|
-
# would do, we pull it up here and get a real method written so that
|
61
|
-
# things get dispatched properly.
|
62
|
-
config_attr_writer :daemonize do |v|
|
63
|
-
configure do |c|
|
64
|
-
c[:daemonize] = v
|
65
|
-
end
|
66
|
-
end
|
66
|
+
# Configuration Settings
|
67
|
+
config_file "/etc/souffle/souffle.rb"
|
67
68
|
|
68
|
-
|
69
|
-
|
69
|
+
# Enable debug
|
70
|
+
debug false
|
70
71
|
|
71
|
-
|
72
|
-
|
72
|
+
# Logging Settings
|
73
|
+
log_level :info
|
74
|
+
log_location STDOUT
|
73
75
|
|
74
|
-
|
76
|
+
# Chef Settings
|
77
|
+
chef_cookbook_path []
|
78
|
+
chef_provisioner :solo
|
79
|
+
chef_domain "souffle"
|
80
|
+
|
81
|
+
# Provider Settings
|
82
|
+
provider "Vagrant"
|
83
|
+
|
84
|
+
# Daemonization Settings
|
85
|
+
user nil
|
86
|
+
group nil
|
87
|
+
umask 0022
|
88
|
+
|
89
|
+
pid_file nil
|
90
|
+
|
91
|
+
# AWS Settings
|
92
|
+
aws_access_key ""
|
93
|
+
aws_access_secret ""
|
94
|
+
aws_region "us-west-1"
|
95
|
+
delete_on_termination true
|
96
|
+
|
97
|
+
# Rack Settings
|
98
|
+
rack_host "0.0.0.0"
|
99
|
+
rack_port 8080
|
100
|
+
rack_environment "development"
|
101
|
+
|
102
|
+
# Vagrant Settings
|
103
|
+
vagrant_dir "#{ENV['HOME']}/vagrant/vms"
|
75
104
|
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'etc'
|
2
|
+
|
3
|
+
# Daemon helper routines.
|
4
|
+
class Souffle::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
|
+
Souffle::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
|
+
Souffle::Log.info(msg)
|
22
|
+
File.umask Souffle::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
|
+
Souffle::Application.fatal!("There is no fork: #{e.message}")
|
30
|
+
end
|
31
|
+
else
|
32
|
+
Souffle::Application.fatal!("Souffle is already running pid #{pid}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Checks if Souffle is running based on the pid_file.
|
37
|
+
#
|
38
|
+
# @return [ Boolean ] Whether or not Souffle 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
|
+
Souffle::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
|
+
Souffle::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
|
64
|
+
# exist.
|
65
|
+
def pid_from_file
|
66
|
+
File.read(pid_file).chomp.to_i
|
67
|
+
rescue Errno::ENOENT, Errno::EACCES
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Store the PID on the filesystem.
|
72
|
+
#
|
73
|
+
# @note
|
74
|
+
# This uses the Souffle::Config[:pid_file] option or "/tmp/name.pid"
|
75
|
+
# by default.
|
76
|
+
def save_pid_file
|
77
|
+
file = pid_file
|
78
|
+
begin
|
79
|
+
FileUtils.mkdir_p(File.dirname(file))
|
80
|
+
rescue Errno::EACCES => e
|
81
|
+
msg = "Failed store pid in #{File.dirname(file)}, "
|
82
|
+
msg << "permission denied: #{e.message}"
|
83
|
+
Souffle::Application.fatal!(msg)
|
84
|
+
end
|
85
|
+
|
86
|
+
begin
|
87
|
+
File.open(file, "w") { |f| f.write(Process.pid.to_s) }
|
88
|
+
rescue Errno::EACCES => e
|
89
|
+
msg = "Couldn't write to pidfile #{file}, "
|
90
|
+
msg << "permission denied: #{e.message}"
|
91
|
+
Souffle::Application.fatal!(msg)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Delete the PID from the filesystem
|
96
|
+
def remove_pid_file
|
97
|
+
FileUtils.rm(pid_file) if File.exists?(pid_file)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Change process user/group to those specified in Souffle::Config
|
101
|
+
def change_privilege
|
102
|
+
Dir.chdir("/")
|
103
|
+
|
104
|
+
msg = "About to change privilege to "
|
105
|
+
if Souffle::Config[:user] and Souffle::Config[:group]
|
106
|
+
msg << "#{Souffle::Config[:user]}:#{Souffle::Config[:group]}"
|
107
|
+
Souffle::Log.info(msg)
|
108
|
+
_change_privilege(Souffle::Config[:user], Souffle::Config[:group])
|
109
|
+
elsif Souffle::Config[:user]
|
110
|
+
msg << "#{Souffle::Config[:user]}"
|
111
|
+
Souffle::Log.info(msg)
|
112
|
+
_change_privilege(Souffle::Config[:user])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Change privileges of the process to be the specified user and group
|
117
|
+
#
|
118
|
+
# @param [ String ] user The user to change the process to.
|
119
|
+
# @param [ String ] group The group to change the process to.
|
120
|
+
#
|
121
|
+
# @note
|
122
|
+
# The group parameter defaults to user unless specified.
|
123
|
+
def _change_privilege(user, group=user)
|
124
|
+
uid, gid = Process.euid, Process.egid
|
125
|
+
|
126
|
+
begin
|
127
|
+
target_uid = Etc.getpwnam(user).uid
|
128
|
+
rescue ArgumentError => e
|
129
|
+
msg = "Failed to get UID for user #{user}, does it exist? "
|
130
|
+
msg << e.message
|
131
|
+
Souffle::Application.fatal!(msg)
|
132
|
+
return false
|
133
|
+
end
|
134
|
+
|
135
|
+
begin
|
136
|
+
target_gid = Etc.getgrnam(group).gid
|
137
|
+
rescue ArgumentError => e
|
138
|
+
msg = "Failed to get GID for group #{group}, does it exist? "
|
139
|
+
msg << e.message
|
140
|
+
Souffle::Application.fatal!(msg)
|
141
|
+
return false
|
142
|
+
end
|
143
|
+
|
144
|
+
if (uid != target_uid) or (gid != target_gid)
|
145
|
+
Process.initgroups(user, target_gid)
|
146
|
+
Process::GID.change_privilege(target_gid)
|
147
|
+
Process::UID.change_privilege(target_uid)
|
148
|
+
end
|
149
|
+
true
|
150
|
+
rescue Errno::EPERM => e
|
151
|
+
msg = "Permission denied when trying to change #{uid}:#{gid} "
|
152
|
+
msg << "to #{target_uid}:#{target_gid}. #{e.message}"
|
153
|
+
Souffle::Application.fatal!(msg)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|