baal 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +117 -0
- data/Rakefile +6 -0
- data/baal.gemspec +28 -0
- data/lib/baal.rb +75 -0
- data/lib/baal/commands.rb +105 -0
- data/lib/baal/matching_options.rb +125 -0
- data/lib/baal/optional_options.rb +297 -0
- data/lib/baal/version.rb +3 -0
- metadata +116 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 9fd791002dfcce1998043d8c2933dfe4916f711f
|
|
4
|
+
data.tar.gz: 6eb46c2f1680ef7c4134452324139ad4589c4af1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 9242ed3fc57795d76a102afa72f3cd3eeb2d859461efcdea523109d4e8461ea216baac53137aeea4c57ce0fe5d2878b1075bede930dd77ac7015770bd09586fb
|
|
7
|
+
data.tar.gz: e70d24a8b3af1051f6af9cab25058b131969bb6b3d97ed6662f7fc35bcd7b23085e246e779aae1b7fe83bc94e6b4cc0d1536e0c9adbcdbbca9f12a0298c251ca
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 Lukas Nimmo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Baal
|
|
2
|
+
|
|
3
|
+
Baal is a Ruby wrapper for start-stop-daemon that attempts to make your start-stop-daemon scripts easier to build and
|
|
4
|
+
read while still providing the same options you are used to. Baal, through start-stop-daemon, provides a myriad of ways
|
|
5
|
+
to start new daemon processes and check the status of and stop existing ones.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'baal'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
$ bundle
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
$ gem install baal
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
The intention of Baal is to provide an easily-readable, step-by-step process of building start-stop-daemon scripts.
|
|
26
|
+
|
|
27
|
+
The wrapper provides all methods you are used to and attempts to alert you (with a nice red error) if it notices a mistake.
|
|
28
|
+
|
|
29
|
+
All building is centered around the Daemon object which can be accessed like so:
|
|
30
|
+
|
|
31
|
+
```ruby
|
|
32
|
+
# Preferred
|
|
33
|
+
daemon = Baal.new
|
|
34
|
+
|
|
35
|
+
# Not preferred
|
|
36
|
+
daemon = Baal::Daemon.new
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Once you have your builder object, it is simply a matter of constructing the needed commands and options.
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
# Start a new process in the background
|
|
43
|
+
daemon.start
|
|
44
|
+
daemon.instance_of_exec('/abs/path/to/executable')
|
|
45
|
+
daemon.with_name('dave')
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Then execute what you have built
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
daemon.daemonize!
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You can even check the current status of what you are to execute
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
puts daemon.execution
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
You can also clear the current contents of what you have built up
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
# Begin with start
|
|
64
|
+
daemon.start
|
|
65
|
+
daemon.start_as('/path/to/file')
|
|
66
|
+
daemon.pid_file('/path/to/pid_file')
|
|
67
|
+
|
|
68
|
+
# Something came up! Need to clear it...
|
|
69
|
+
daemon.clear_all!
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
All of the methods that build up your start-stop-daemon script are chain-able
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
# Check the status of a process
|
|
77
|
+
daemon.status.with_pid(1234).daemonize!
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
All options with dashes have been converted to underscores, ie.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
# From
|
|
84
|
+
daemon.make-pidfile
|
|
85
|
+
|
|
86
|
+
# To
|
|
87
|
+
daemon.make_pidfile
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
and there are many methods that have been written to be more Ruby-like, however, if you still prefer the original
|
|
91
|
+
command and option names (dashes are not allowed), those are available as well
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
# These are just options...
|
|
95
|
+
daemon.start.start_as('/p/a/t/h').pid_file('/p/a/t/h').change_to_user('dave')
|
|
96
|
+
|
|
97
|
+
# Original language
|
|
98
|
+
daemon.start.startas('/p/a/t/h').pidfile('/p/a/t/h').chuid('dave')
|
|
99
|
+
|
|
100
|
+
# No option for multi-word options with dashes
|
|
101
|
+
daemon.make-pidfile # No method
|
|
102
|
+
daemon.make_pidfile # As above
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The documentation in the library should be enough, but if it isn't, or you just don't like my writing style, then there
|
|
106
|
+
is the official [documention](https://manpages.debian.org/jessie/dpkg/start-stop-daemon.8.en.html) of start-stop-daemon.
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
|
|
110
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/numbluk/baal.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
Copyright (c) 2017 Lukas Nimmo.
|
|
115
|
+
|
|
116
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
117
|
+
|
data/Rakefile
ADDED
data/baal.gemspec
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'baal/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'baal'
|
|
8
|
+
spec.version = Baal::VERSION
|
|
9
|
+
spec.authors = ['Lukas Nimmo']
|
|
10
|
+
spec.email = ['Lukas.nimmo@gmail.com']
|
|
11
|
+
|
|
12
|
+
spec.summary = <<-HEREDOC
|
|
13
|
+
Baal is a Ruby wrapper for start-stop-daemon that attempts to make your start-stop-daemon scripts easier to build
|
|
14
|
+
and read while still providing the same options you are used to. Baal, through start-stop-daemon, provides a
|
|
15
|
+
myriad of ways to start new daemon processes and check the status of and stop existing ones.
|
|
16
|
+
HEREDOC
|
|
17
|
+
spec.homepage = 'https://github.com/numbluk/baal'
|
|
18
|
+
spec.license = 'MIT'
|
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
|
21
|
+
end
|
|
22
|
+
spec.require_paths = ['lib']
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
27
|
+
spec.add_development_dependency 'pry', '~> 3.0'
|
|
28
|
+
end
|
data/lib/baal.rb
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'baal/version'
|
|
2
|
+
require 'baal/commands'
|
|
3
|
+
require 'baal/matching_options'
|
|
4
|
+
require 'baal/optional_options'
|
|
5
|
+
|
|
6
|
+
# The Baal module is the namespace containing all interaction with the Baal gem.
|
|
7
|
+
# Very little is actually done directly on the Baal module. The primary
|
|
8
|
+
# interaction with the Baal module itself will be the instantiation of a Daemon
|
|
9
|
+
# object with the convenience method #new:
|
|
10
|
+
#
|
|
11
|
+
# 1. Baal.new
|
|
12
|
+
#
|
|
13
|
+
# vs
|
|
14
|
+
#
|
|
15
|
+
# 2. Baal::Daemon.new
|
|
16
|
+
#
|
|
17
|
+
module Baal
|
|
18
|
+
def self.new
|
|
19
|
+
Daemon.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Daemon is a builder object that allows you construct and access, at any
|
|
23
|
+
# time, the start-stop-daemon string that will be executed. All building
|
|
24
|
+
# of the start-stop-daemon string will be through this object.
|
|
25
|
+
#
|
|
26
|
+
# A note should be made that all methods which build the start-stop-daemon
|
|
27
|
+
# script return the Daemon instance for the intention of method chaining
|
|
28
|
+
# where possible so as to read like written English.
|
|
29
|
+
#
|
|
30
|
+
class Daemon
|
|
31
|
+
include Baal::Commands
|
|
32
|
+
include Baal::MatchingOptions
|
|
33
|
+
include Baal::OptionalOptions
|
|
34
|
+
|
|
35
|
+
PROGRAM_NAME = 'start-stop-daemon'.freeze
|
|
36
|
+
|
|
37
|
+
def initialize
|
|
38
|
+
@execution = [PROGRAM_NAME]
|
|
39
|
+
@testing = false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# TODO: Add method to remove a single command or option
|
|
43
|
+
|
|
44
|
+
# Clears @execution and starts over with only the PROGRAM_NAME
|
|
45
|
+
#
|
|
46
|
+
def clear_all!
|
|
47
|
+
@execution.clear
|
|
48
|
+
@execution = [PROGRAM_NAME]
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @return [String] the built up, whitespace-formatted start-stop-daemon
|
|
53
|
+
# string to be executed
|
|
54
|
+
#
|
|
55
|
+
def execution
|
|
56
|
+
@execution.join(' ').strip
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Executes the built up start-stop-daemon string and throws an error if
|
|
60
|
+
# there isn't at least one command and at least one matching option.
|
|
61
|
+
#
|
|
62
|
+
# @return [true, false, nil]
|
|
63
|
+
# true: if command was successful (exit status 0)
|
|
64
|
+
# false: if command was unsuccessful (exit status non-zero)
|
|
65
|
+
# nil: if command execution fails
|
|
66
|
+
#
|
|
67
|
+
# TODO: remove usage of system
|
|
68
|
+
#
|
|
69
|
+
def daemonize!
|
|
70
|
+
at_least_one_command?
|
|
71
|
+
at_least_one_matching_option?
|
|
72
|
+
system @execution
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Baal
|
|
2
|
+
|
|
3
|
+
# Commands contains all of the necessary methods to perform all of the
|
|
4
|
+
# possible start-stop-daemon commands.
|
|
5
|
+
#
|
|
6
|
+
module Commands
|
|
7
|
+
# Hash constant containing all possible commands.
|
|
8
|
+
COMMANDS = {
|
|
9
|
+
start: '--start',
|
|
10
|
+
stop: '--stop',
|
|
11
|
+
status: '--status',
|
|
12
|
+
help: '--help',
|
|
13
|
+
version: '--version'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
# Command that attempts to start a process specified through an option.
|
|
17
|
+
# Initially, it will check whether or not a specified process (through an
|
|
18
|
+
# option) exits. Then it will do one of the following:
|
|
19
|
+
#
|
|
20
|
+
# 1. If a specified process already exists then it will do nothing and exit
|
|
21
|
+
# with an error status of 1 (or 0 if oknodo option is specified).
|
|
22
|
+
#
|
|
23
|
+
# 2. If a matching process does not exist, then it will start an instance of
|
|
24
|
+
# one using one of the following options:
|
|
25
|
+
#
|
|
26
|
+
# I. exec: an absolute pathname to an executable
|
|
27
|
+
#
|
|
28
|
+
# II. start_as: a path_name to a process
|
|
29
|
+
#
|
|
30
|
+
def start
|
|
31
|
+
@execution.insert 1, COMMANDS[:start]
|
|
32
|
+
include_multiple_commands?
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Command that attempts to stop a specified process. Initially, it will
|
|
37
|
+
# check whether or not a specified process (through an option) exists. Then
|
|
38
|
+
# it will do one the following:
|
|
39
|
+
#
|
|
40
|
+
# 1. If a process DOES exist it will send it a signal specified by the
|
|
41
|
+
# option:
|
|
42
|
+
#
|
|
43
|
+
# signal: the signal to be sent to processes being stopped. If none
|
|
44
|
+
# specified then it defaults to TERM
|
|
45
|
+
#
|
|
46
|
+
# 2. If a process DOES NOT exist it it will exit with an error status of 1
|
|
47
|
+
# (or 1 if the oknodo option is specified).
|
|
48
|
+
#
|
|
49
|
+
# 3. If the following option is specified then start-stop-daemon will check
|
|
50
|
+
# that the process(es) have finished:
|
|
51
|
+
#
|
|
52
|
+
# retry: option to check whether or not process(es) finish
|
|
53
|
+
#
|
|
54
|
+
def stop
|
|
55
|
+
@execution.insert 1, COMMANDS[:stop]
|
|
56
|
+
include_multiple_commands?
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
alias kill stop
|
|
60
|
+
|
|
61
|
+
# Command that checks for whether or not a process specified by an option
|
|
62
|
+
# exists. An exit code is returned accord to the LSB Init Script Actions.
|
|
63
|
+
# TODO: provide better error messages based on LSB.
|
|
64
|
+
def status
|
|
65
|
+
@execution.insert 1, COMMANDS[:status]
|
|
66
|
+
include_multiple_commands?
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Command that shows cli help information and then exits.
|
|
71
|
+
def help
|
|
72
|
+
@execution.insert 1, COMMANDS[:help]
|
|
73
|
+
include_multiple_commands?
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Command that shows your program version of start-stop-daemon and then
|
|
78
|
+
# exits.
|
|
79
|
+
def version
|
|
80
|
+
@execution.insert 1, COMMANDS[:version]
|
|
81
|
+
include_multiple_commands?
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
# TODO: Added better errors?
|
|
88
|
+
def include_multiple_commands?
|
|
89
|
+
command_count = 0
|
|
90
|
+
COMMANDS.each do |_, command|
|
|
91
|
+
command_count += 1 if execution.include? command
|
|
92
|
+
|
|
93
|
+
raise ArgumentError, 'You can only have one command.' if command_count > 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def at_least_one_command?
|
|
98
|
+
COMMANDS.each do |_, command|
|
|
99
|
+
return if execution.include? command
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
raise ArgumentError, 'You must have at least one command.'
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module Baal
|
|
2
|
+
|
|
3
|
+
# MatchingOptions is a container for all methods relating to adding Matching
|
|
4
|
+
# Options to your start-stop-daemon script. Matching Options are used to
|
|
5
|
+
# target existing processes or identify new ones to be acted upon using a
|
|
6
|
+
# Command.
|
|
7
|
+
#
|
|
8
|
+
# At least one Matching Option is required to execute a start-stop-daemon
|
|
9
|
+
# script.
|
|
10
|
+
#
|
|
11
|
+
module MatchingOptions
|
|
12
|
+
# All possible Matching Options
|
|
13
|
+
MATCHING_OPTIONS = {
|
|
14
|
+
pid: '--pid',
|
|
15
|
+
ppid: '--ppid',
|
|
16
|
+
pid_file: '--pidfile',
|
|
17
|
+
exec: '--exec',
|
|
18
|
+
name: '--name',
|
|
19
|
+
user: '--user'
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
# Checks for a process with a specified process id.
|
|
23
|
+
#
|
|
24
|
+
# @param id [String, Integer] the process id to be targeted. Must be
|
|
25
|
+
# greater than 0.
|
|
26
|
+
# TODO: Add error to catch for 0 or less.
|
|
27
|
+
#
|
|
28
|
+
def pid(id)
|
|
29
|
+
@execution.push "#{MATCHING_OPTIONS[:pid]}=#{id}"
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
alias with_pid pid
|
|
33
|
+
|
|
34
|
+
# Checks for a process with a specified parent process id.
|
|
35
|
+
#
|
|
36
|
+
# @param id [String, Integer] the parent process id to be targeted. Must be
|
|
37
|
+
# greater than 0.
|
|
38
|
+
# TODO: Add error to catch for 0 or less.
|
|
39
|
+
#
|
|
40
|
+
def ppid(id)
|
|
41
|
+
@execution.push "#{MATCHING_OPTIONS[:ppid]}=#{id}"
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
alias with_ppid ppid
|
|
45
|
+
|
|
46
|
+
# Checks whether or not a process has created the pid_file.
|
|
47
|
+
#
|
|
48
|
+
# @param path [String] the path to the pid_file to be checked.
|
|
49
|
+
#
|
|
50
|
+
# WARNING: if used alone AND the old process terminated without removing
|
|
51
|
+
# the pid_file specified by @path, then this might cause
|
|
52
|
+
# unintended consequences.
|
|
53
|
+
#
|
|
54
|
+
def pid_file(path)
|
|
55
|
+
@execution.push "#{MATCHING_OPTIONS[:pid_file]}=#{path}"
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
alias with_pid_file pid_file
|
|
59
|
+
alias pidfile pid_file
|
|
60
|
+
|
|
61
|
+
# Used with Commands#start.
|
|
62
|
+
#
|
|
63
|
+
# Checks for processes that are instances of the executable specified by
|
|
64
|
+
# abs_path_to_exec.
|
|
65
|
+
#
|
|
66
|
+
# @param abs_path_to_exec [String] the absolute path to the executable
|
|
67
|
+
#
|
|
68
|
+
# NOTE: might not work if used with interpreted scripts, as the executable
|
|
69
|
+
# will point to the interpreter.
|
|
70
|
+
#
|
|
71
|
+
# WARNING: take into account processes running from inside a chroot will
|
|
72
|
+
# also be identified, so other restrictions might be needed to
|
|
73
|
+
# avoid this.
|
|
74
|
+
#
|
|
75
|
+
def exec(abs_path_to_exec)
|
|
76
|
+
@execution.push "#{MATCHING_OPTIONS[:exec]}=#{abs_path_to_exec}"
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
alias instance_of_exec exec
|
|
80
|
+
|
|
81
|
+
# Checks for processes with the name specified by @process_name
|
|
82
|
+
#
|
|
83
|
+
# @param process_name [String] name of process
|
|
84
|
+
#
|
|
85
|
+
# NOTE: the name of the process is often the filename, but be wary that it
|
|
86
|
+
# could have been changed by process itself
|
|
87
|
+
#
|
|
88
|
+
# NOTE: for most systems the process name is retrieved from the process
|
|
89
|
+
# comm name from the kernel. This is typically a shortened version
|
|
90
|
+
# of the expected process name that is 15 characters long.
|
|
91
|
+
#
|
|
92
|
+
def name(process_name)
|
|
93
|
+
@execution.push "#{MATCHING_OPTIONS[:name]}=#{process_name}"
|
|
94
|
+
self
|
|
95
|
+
end
|
|
96
|
+
alias with_name name
|
|
97
|
+
|
|
98
|
+
# Checks for processes owned by the user specified by a username or uid.
|
|
99
|
+
#
|
|
100
|
+
# @param username_or_uid [String, Symbol, Integer]
|
|
101
|
+
#
|
|
102
|
+
# WARNING: Using this matching option ALONE will cause all matching
|
|
103
|
+
# processes to be acted upon.
|
|
104
|
+
#
|
|
105
|
+
def user(username_or_uid)
|
|
106
|
+
@execution.push "#{MATCHING_OPTIONS[:user]}=#{username_or_uid}"
|
|
107
|
+
self
|
|
108
|
+
end
|
|
109
|
+
alias username user
|
|
110
|
+
alias uid user
|
|
111
|
+
alias owned_by_user user
|
|
112
|
+
alias owned_by_username user
|
|
113
|
+
alias owned_by_uid user
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def at_least_one_matching_option?
|
|
118
|
+
MATCHING_OPTIONS.each do |_, option|
|
|
119
|
+
return if execution.include? option
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
raise ArgumentError, 'You must have at least one matching option.'
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
module Baal
|
|
2
|
+
|
|
3
|
+
# Optional Options is a container for all methods relating to options that
|
|
4
|
+
# can be added to your start-stop-daemon script, but are not required
|
|
5
|
+
#
|
|
6
|
+
module OptionalOptions
|
|
7
|
+
class InvalidPolicyError < ArgumentError; end
|
|
8
|
+
class InvalidScheduleClassError < ArgumentError; end
|
|
9
|
+
|
|
10
|
+
# All optional options
|
|
11
|
+
OPTIONAL_OPTS = {
|
|
12
|
+
group: '--group',
|
|
13
|
+
signal: '--signal',
|
|
14
|
+
retry: '--retry',
|
|
15
|
+
start_as: '--startas',
|
|
16
|
+
test: '--test',
|
|
17
|
+
oknodo: '--oknodo',
|
|
18
|
+
quiet: '--quiet',
|
|
19
|
+
chuid: '--chuid',
|
|
20
|
+
chroot: '--chroot',
|
|
21
|
+
chdir: '--chdir',
|
|
22
|
+
background: '--background',
|
|
23
|
+
no_close: '--no-close',
|
|
24
|
+
nice_level: '--nicelevel',
|
|
25
|
+
proc_sched: '--procsched',
|
|
26
|
+
io_sched: '--iosched',
|
|
27
|
+
umask: '--umask',
|
|
28
|
+
make_pid_file: '--make-pidfile',
|
|
29
|
+
remove_pid_file: '--remove-pidfile',
|
|
30
|
+
verbose: '--verbose'
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
# Change to a group or group id before starting the process
|
|
34
|
+
#
|
|
35
|
+
# @param group_name_or_gid [String, Integer, Symbol] the group name or group
|
|
36
|
+
# id to be changed to
|
|
37
|
+
#
|
|
38
|
+
def group(group_name_or_gid)
|
|
39
|
+
@execution.push "#{OPTIONAL_OPTS[:group]}=#{group_name_or_gid}"
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
alias group_name group
|
|
43
|
+
alias gid group
|
|
44
|
+
alias change_to_group group
|
|
45
|
+
alias change_to_group_name group
|
|
46
|
+
alias change_to_gid group
|
|
47
|
+
|
|
48
|
+
# Used with Commands#stop. Specifies the signal to send to the
|
|
49
|
+
# processes attempting to be stopped.
|
|
50
|
+
#
|
|
51
|
+
# @param signal[String, Symbol] the signal to send
|
|
52
|
+
#
|
|
53
|
+
def signal(signal = 'TERM')
|
|
54
|
+
@execution.push "#{OPTIONAL_OPTS[:signal]}=#{signal}"
|
|
55
|
+
self
|
|
56
|
+
end
|
|
57
|
+
alias with_signal signal
|
|
58
|
+
|
|
59
|
+
# Used with Commands#stop. Specifies that start-stop-daemon is to check
|
|
60
|
+
# whether the process(es) do finish. It will check repeatedly whether any
|
|
61
|
+
# matching processes are running, until none are. If the processes do not
|
|
62
|
+
# exit it will then take futher action as defined by the schedule.
|
|
63
|
+
#
|
|
64
|
+
# @param timeout_or_schedule [String, Integer]
|
|
65
|
+
# If a timeout (in seconds) is specified, then the following schedule is
|
|
66
|
+
# used:
|
|
67
|
+
#
|
|
68
|
+
# signal/timeout/KILL/timeout, where signal is specified with
|
|
69
|
+
# OptionalOptions#signal.
|
|
70
|
+
#
|
|
71
|
+
# To specify a schedule: a schedule is a list of at least two items
|
|
72
|
+
# separated by slashes; each item may be any of the following:
|
|
73
|
+
#
|
|
74
|
+
# 1. signal number or signal name, which means to send that signal
|
|
75
|
+
# 2. timeout, which means to wait that many seconds for processes to
|
|
76
|
+
# exit
|
|
77
|
+
# 3. forever, which means to repeat the rest of the schedule forever if
|
|
78
|
+
# necessary
|
|
79
|
+
#
|
|
80
|
+
# If the end of the schedule is reached and forever is not specified, then
|
|
81
|
+
# start-stop-daemon exits with the error status of 2.
|
|
82
|
+
#
|
|
83
|
+
# WARNING: If a schedule is specified, then any signal specified with
|
|
84
|
+
# OptionalOptions#signal is ignored.
|
|
85
|
+
#
|
|
86
|
+
# TODO: Add better arguments for constructing a schedule
|
|
87
|
+
#
|
|
88
|
+
def retry(timeout_or_schedule)
|
|
89
|
+
@execution.push "#{OPTIONAL_OPTS[:retry]}=#{timeout_or_schedule}"
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
alias retry_timeout retry
|
|
93
|
+
alias retry_schedule retry
|
|
94
|
+
|
|
95
|
+
# Used with Commands#start.
|
|
96
|
+
#
|
|
97
|
+
# Starts the process at the specified path. If not added as an option to
|
|
98
|
+
# Commands#start, the path will default to the one provided to
|
|
99
|
+
# MatchhingOptions#exec.
|
|
100
|
+
#
|
|
101
|
+
# @param path [String] path to process to attempt to start as
|
|
102
|
+
#
|
|
103
|
+
def start_as(path)
|
|
104
|
+
@execution.push "#{OPTIONAL_OPTS[:start_as]}=#{path}"
|
|
105
|
+
self
|
|
106
|
+
end
|
|
107
|
+
alias startas start_as
|
|
108
|
+
|
|
109
|
+
# Print actions that would be taken and set an appropriate return value,
|
|
110
|
+
# but take no action
|
|
111
|
+
#
|
|
112
|
+
def test
|
|
113
|
+
@execution.push OPTIONAL_OPTS[:test]
|
|
114
|
+
self
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Return an exit status of 0 instead of 1 if no actions are, or would not
|
|
118
|
+
# be, taken
|
|
119
|
+
#
|
|
120
|
+
def oknodo
|
|
121
|
+
@execution.push OPTIONAL_OPTS[:oknodo]
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Do not print informational messages; only display error messages
|
|
126
|
+
#
|
|
127
|
+
def quiet
|
|
128
|
+
@execution.push OPTIONAL_OPTS[:quiet]
|
|
129
|
+
self
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Change to the specified username or uid before starting the process.
|
|
133
|
+
#
|
|
134
|
+
# @param username_or_uid [String, Integer, Symbol] username or uid to change
|
|
135
|
+
# to.
|
|
136
|
+
# @param group_or_gid [String, Integer, Symbol] group name or group id to
|
|
137
|
+
# change to.
|
|
138
|
+
#
|
|
139
|
+
# NOTE: If a user is specified without a group, the primary GID for that
|
|
140
|
+
# user is used.
|
|
141
|
+
#
|
|
142
|
+
# NOTE: Primary and supplemental groups are set as well, even if the
|
|
143
|
+
# OptionalOptions#group option is not specified. The
|
|
144
|
+
# OptionalOptions#group option is only groups that the user isn't
|
|
145
|
+
# normally a member of.
|
|
146
|
+
#
|
|
147
|
+
def chuid(username_or_uid, group_or_gid = nil)
|
|
148
|
+
group_or_gid = group_or_gid.nil? ? '' : ":#{group_or_gid}"
|
|
149
|
+
@execution.push "#{OPTIONAL_OPTS[:chuid]}=#{username_or_uid}#{group_or_gid}"
|
|
150
|
+
self
|
|
151
|
+
end
|
|
152
|
+
alias change_to_user chuid
|
|
153
|
+
alias change_to_uid chuid
|
|
154
|
+
|
|
155
|
+
# Change directories and chroot to root before starting the process.
|
|
156
|
+
#
|
|
157
|
+
# @param new_root_dir [String] path to chroot to
|
|
158
|
+
#
|
|
159
|
+
# NOTE: the pid_file is written after the chroot
|
|
160
|
+
#
|
|
161
|
+
def chroot(new_root_dir)
|
|
162
|
+
@execution.push "#{OPTIONAL_OPTS[:chroot]}=#{new_root_dir}"
|
|
163
|
+
self
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Change directories to @path before starting the process.
|
|
167
|
+
#
|
|
168
|
+
# Chdir is done AFTER the chroot if the OptionalOptions#chroot option is
|
|
169
|
+
# set. When no OptionalOptions#chroot is set, start-stop-daemon will
|
|
170
|
+
# chdir to the root directory before starting the process.
|
|
171
|
+
#
|
|
172
|
+
def chdir(path)
|
|
173
|
+
@execution.push "#{OPTIONAL_OPTS[:chdir]}=#{path}"
|
|
174
|
+
self
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def background
|
|
178
|
+
@execution.push OPTIONAL_OPTS[:background]
|
|
179
|
+
self
|
|
180
|
+
end
|
|
181
|
+
alias in_background background
|
|
182
|
+
|
|
183
|
+
# Only relevant when using --background
|
|
184
|
+
def no_close
|
|
185
|
+
@execution.push OPTIONAL_OPTS[:no_close]
|
|
186
|
+
self
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Alters the priority of the process before starting it.
|
|
190
|
+
#
|
|
191
|
+
# @param incr [String, Integer] amount to alter the priority level, can be
|
|
192
|
+
# positive or negative
|
|
193
|
+
#
|
|
194
|
+
def nice_level(incr)
|
|
195
|
+
@execution.push "#{OPTIONAL_OPTS[:nice_level]}=#{incr}"
|
|
196
|
+
self
|
|
197
|
+
end
|
|
198
|
+
alias incr_nice_level nice_level
|
|
199
|
+
|
|
200
|
+
VALID_POLICIES = %w(other fifo rr).freeze
|
|
201
|
+
|
|
202
|
+
# Alters the process scheduler class and priority of the process before
|
|
203
|
+
# starting it.
|
|
204
|
+
#
|
|
205
|
+
# Default priority is 0 when executed.
|
|
206
|
+
#
|
|
207
|
+
# @param policy [String, Symbol] the process scheduler policy.
|
|
208
|
+
# Supported values: :other, :fifo, :rr
|
|
209
|
+
# @param priority [String, Integer] the process priority
|
|
210
|
+
def proc_sched(policy, priority = nil)
|
|
211
|
+
unless VALID_POLICIES.include? policy.to_s
|
|
212
|
+
raise InvalidPolicyError, 'Invalid policy. Expected: other, fifo, rr'
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
priority = priority.nil? ? ' ' : ":#{priority}"
|
|
216
|
+
@execution.push "#{OPTIONAL_OPTS[:proc_sched]}=#{policy}#{priority}"
|
|
217
|
+
self
|
|
218
|
+
end
|
|
219
|
+
alias procshed proc_sched
|
|
220
|
+
alias process_schedule proc_sched
|
|
221
|
+
|
|
222
|
+
VALID_SCHEDULE_CLASSES = %w(idle best-effort real-time).freeze
|
|
223
|
+
|
|
224
|
+
# Alters the io IO scheduler class and priority of the process before
|
|
225
|
+
# starting it.
|
|
226
|
+
#
|
|
227
|
+
# Default priority is 4, unless the sched_class is :idle, then it's 7.
|
|
228
|
+
#
|
|
229
|
+
# @param sched_class [String, Symbol] the io scheduler class.
|
|
230
|
+
# Supported values: :idle, :best-effort, :real-time
|
|
231
|
+
# @param priority [String, Integer] the process priority.
|
|
232
|
+
#
|
|
233
|
+
def io_sched(sched_class, priority = nil)
|
|
234
|
+
puts sched_class
|
|
235
|
+
unless VALID_SCHEDULE_CLASSES.include? sched_class.to_s
|
|
236
|
+
raise InvalidScheduleClassError,
|
|
237
|
+
'Invalid schedule class. Expected: idle, best-effort, real-time'
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
priority = priority.nil? ? ' ' : ":#{priority}"
|
|
241
|
+
@execution.push "#{OPTIONAL_OPTS[:io_sched]}=#{sched_class}#{priority}"
|
|
242
|
+
self
|
|
243
|
+
end
|
|
244
|
+
alias iosched io_sched
|
|
245
|
+
alias io_schedule io_sched
|
|
246
|
+
|
|
247
|
+
# Sets the umask of the process before starting it
|
|
248
|
+
#
|
|
249
|
+
# @param mask [String, Integer] umask value
|
|
250
|
+
def umask(mask)
|
|
251
|
+
@execution.push "#{OPTIONAL_OPTS[:umask]}=#{mask}"
|
|
252
|
+
self
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Used when starting a program that does not create its own pid file.
|
|
256
|
+
#
|
|
257
|
+
# Used together with the file specified by the MatchingOptions#pidfile
|
|
258
|
+
# option.
|
|
259
|
+
#
|
|
260
|
+
# This will place the pid into the file specified by the
|
|
261
|
+
# MatchingOptions#pidfile option, just before executing the process.
|
|
262
|
+
#
|
|
263
|
+
# NOTE: The file will only be removed if the OptionalOptions#remove_pid_file
|
|
264
|
+
# option is used.
|
|
265
|
+
#
|
|
266
|
+
# WARNING: Will not work in all cases, such as when the program being
|
|
267
|
+
# executed forks from its main process. Because of this, it is
|
|
268
|
+
# usually only useful when combined with the
|
|
269
|
+
# OptionalOptions#background option.
|
|
270
|
+
#
|
|
271
|
+
def make_pid_file
|
|
272
|
+
@execution.push OPTIONAL_OPTS[:make_pid_file]
|
|
273
|
+
self
|
|
274
|
+
end
|
|
275
|
+
alias make_pidfile make_pid_file
|
|
276
|
+
|
|
277
|
+
# Used when stopping a program that will NOT remove its own pid file.
|
|
278
|
+
#
|
|
279
|
+
# Used together with the file specified by the MatchingOptions#pidfile
|
|
280
|
+
# option.
|
|
281
|
+
#
|
|
282
|
+
# This will remove the file specified by the MatchingOptions#pidfile
|
|
283
|
+
# option.
|
|
284
|
+
#
|
|
285
|
+
def remove_pid_file
|
|
286
|
+
@execution.push OPTIONAL_OPTS[:remove_pid_file]
|
|
287
|
+
self
|
|
288
|
+
end
|
|
289
|
+
alias remove_pidfile remove_pid_file
|
|
290
|
+
|
|
291
|
+
# Print verbose informational messages when executing the script
|
|
292
|
+
def verbose
|
|
293
|
+
@execution.push OPTIONAL_OPTS[:verbose]
|
|
294
|
+
self
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
data/lib/baal/version.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: baal
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Lukas Nimmo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-05-23 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.13'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.13'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rspec
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: pry
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '3.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
description:
|
|
70
|
+
email:
|
|
71
|
+
- Lukas.nimmo@gmail.com
|
|
72
|
+
executables: []
|
|
73
|
+
extensions: []
|
|
74
|
+
extra_rdoc_files: []
|
|
75
|
+
files:
|
|
76
|
+
- ".gitignore"
|
|
77
|
+
- ".rspec"
|
|
78
|
+
- ".travis.yml"
|
|
79
|
+
- Gemfile
|
|
80
|
+
- LICENSE.txt
|
|
81
|
+
- README.md
|
|
82
|
+
- Rakefile
|
|
83
|
+
- baal.gemspec
|
|
84
|
+
- lib/baal.rb
|
|
85
|
+
- lib/baal/commands.rb
|
|
86
|
+
- lib/baal/matching_options.rb
|
|
87
|
+
- lib/baal/optional_options.rb
|
|
88
|
+
- lib/baal/version.rb
|
|
89
|
+
homepage: https://github.com/numbluk/baal
|
|
90
|
+
licenses:
|
|
91
|
+
- MIT
|
|
92
|
+
metadata: {}
|
|
93
|
+
post_install_message:
|
|
94
|
+
rdoc_options: []
|
|
95
|
+
require_paths:
|
|
96
|
+
- lib
|
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - ">="
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - ">="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '0'
|
|
107
|
+
requirements: []
|
|
108
|
+
rubyforge_project:
|
|
109
|
+
rubygems_version: 2.6.8
|
|
110
|
+
signing_key:
|
|
111
|
+
specification_version: 4
|
|
112
|
+
summary: Baal is a Ruby wrapper for start-stop-daemon that attempts to make your start-stop-daemon
|
|
113
|
+
scripts easier to build and read while still providing the same options you are
|
|
114
|
+
used to. Baal, through start-stop-daemon, provides a myriad of ways to start new
|
|
115
|
+
daemon processes and check the status of and stop existing ones.
|
|
116
|
+
test_files: []
|