souffle 0.0.1 → 0.0.2
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/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
|