pazuzu 0.1.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/.gitignore +8 -0
- data/Gemfile +2 -0
- data/Pazuzu.gemspec +29 -0
- data/README.md +171 -0
- data/Rakefile +21 -0
- data/bin/pazuzu +6 -0
- data/bin/pazuzud +6 -0
- data/lib/pazuzu.rb +37 -0
- data/lib/pazuzu/application.rb +114 -0
- data/lib/pazuzu/cgroup.rb +73 -0
- data/lib/pazuzu/command_line/controller.rb +152 -0
- data/lib/pazuzu/control/protocol.rb +304 -0
- data/lib/pazuzu/control/socket_client.rb +30 -0
- data/lib/pazuzu/control/socket_server.rb +75 -0
- data/lib/pazuzu/instance.rb +218 -0
- data/lib/pazuzu/procfiles.rb +16 -0
- data/lib/pazuzu/supervisor.rb +201 -0
- data/lib/pazuzu/supervisor_runner.rb +95 -0
- data/lib/pazuzu/utility/annotated_logger.rb +46 -0
- data/lib/pazuzu/utility/output_tailer.rb +60 -0
- data/lib/pazuzu/utility/process_spawning.rb +40 -0
- data/lib/pazuzu/utility/rate_limiter.rb +68 -0
- data/lib/pazuzu/utility/runnable.rb +120 -0
- data/lib/pazuzu/utility/runnable_pool.rb +62 -0
- data/lib/pazuzu/version.rb +3 -0
- data/lib/pazuzu/worker.rb +173 -0
- metadata +193 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Pazuzu.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
$:.push File.expand_path("../lib", __FILE__)
|
4
|
+
require "pazuzu/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "pazuzu"
|
8
|
+
s.version = Pazuzu::VERSION
|
9
|
+
s.authors = ["Alexander Staubo"]
|
10
|
+
s.email = ["alex@origo.no"]
|
11
|
+
s.homepage = "http://github.com/origo/pazuzu"
|
12
|
+
s.summary = s.description = %{Pazuzu is a supervisor daemon that manages pools of application processes as daemons.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "pazuzu"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency 'activesupport', '~> 3.1.0'
|
22
|
+
s.add_runtime_dependency 'statemachine', '~> 2.0.1'
|
23
|
+
s.add_runtime_dependency 'yajl-ruby', '~> 1.1'
|
24
|
+
s.add_runtime_dependency 'i18n'
|
25
|
+
s.add_runtime_dependency 'scashin133-syslog_logger', '~> 1.7.3'
|
26
|
+
|
27
|
+
s.add_development_dependency "rspec"
|
28
|
+
s.add_development_dependency "rake"
|
29
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
Pazuzu
|
2
|
+
======
|
3
|
+
|
4
|
+
Pazuzu is a supervisor daemon that manages pools of application processes as daemons. Pazuzu uses Heroku's `Procfile` format and relies on Linux cgroups to encapsulate groups of process.
|
5
|
+
|
6
|
+
....
|
7
|
+
......
|
8
|
+
..=?$.. .
|
9
|
+
... ...N~,.... .....
|
10
|
+
.. ..... . ...M8O.... ......
|
11
|
+
......NZ$,.. . ...DD8.... . $O$+....
|
12
|
+
.$8~Z7$. . ....:N88ZO:Z.... ..8ZOD=..
|
13
|
+
. ...8OO7Z$+.... . ..88Z:I=8$?.. ....ZO7I$M.....
|
14
|
+
....DZ+$ZZZ8... . .....?DN878=,~..... . ...N7ODOIDO...
|
15
|
+
....D=ZZ7Z$$?D..... ..M$D8D$D8=I~.... ...N$88IDO8O:....
|
16
|
+
...OOZ$ZO$$?OO.... ...8D8ND8?MM,,... ....8+DZZ7$ZDOO.. .
|
17
|
+
....OZN7$~8Z$7$$.......88O88$~?DO.......=OZZOO8MDOZODN... ..
|
18
|
+
.,D$7I7ZZ$?+$Z8,......ZDDDND8M,......M$OZNDO$NODM8+I..
|
19
|
+
..MDO$Z$DMD+~:Z8:......DDNMM?I,....8Z8Z8Z8N?Z$DDO8D...
|
20
|
+
. ~+D7IN?Z=IOD$ONN.....N8N8~$D..IIOZ78Z$8Z$DO?ZMOOM...
|
21
|
+
...?7DNO=?IDOO8OONDNNNNNNN8OII$I=$Z8Z78D8NZZZZDDD. ..
|
22
|
+
.....MZ$DNDDN?ZZ8DNN8DDDNNNDO7$I$+++ZOOOOO8$NMDI8...
|
23
|
+
....:DOO8NOOZOO8DNNO88DO78O87~~77D=7OO$8OO?NZ?M...
|
24
|
+
...O8ODN$87O8DD8NNND8Z++II:77?7~$$OZOZ$7D+8. .
|
25
|
+
.,8ONNDO~=Z8ZONNNNO=~==:8IN87I=OZZ7ID$7.,..
|
26
|
+
...,8OND88+DZ8DNNNNNDO87+D7D8$$:7Z7Z8Z?.....
|
27
|
+
... ...DNN88NNDONNNNNNNNMZO7$DO8ZZ$7$O7, ...
|
28
|
+
. ...MNDDDDO88DNNNNNDOOMD$DNN=77777,......
|
29
|
+
..,D8ZDO8NDNNNNDD88D78NND8O,$O$.....
|
30
|
+
...OONN8ODDNNNNDD8ZOI$DNDZ8Z7OO?..
|
31
|
+
... .O78O8OZ8DNNNNNNZOI=ODNDOZI~78+...
|
32
|
+
..8O$OZ88NNNNNNNDD8O+$ONN8DD$IZD...
|
33
|
+
.ZDD8OZZDODNDDNNDD$8I+DDNND87O$$$...
|
34
|
+
....N7IOZ8O$O$DNNNNND7O$~,DNDOOZI+78...
|
35
|
+
..=8D8DDNDODZNNNDDNDZOZ:?8DNNZ$~O$8.. .
|
36
|
+
..8DN88DZDDDDNNNNDND8OOO$D8NN88$?=7?...
|
37
|
+
. ...8OM8N8D8DDNNNNNNNDZO7Z+DDNN?I7IM8O...
|
38
|
+
. ..MDDMODOND88NNN8NDMNO$$Z7ZINNMN$NNIZ,
|
39
|
+
..8O88888DDODDNNDNNNON78Z+Z8DMN=N:O8Z?..
|
40
|
+
. .8888OD88M8DNNDONNNM+DOD,+Z$88OZIMD=I..
|
41
|
+
. M8OOO8NDO+8NNNOOZZMDNN8DO?$ZZOO8IDDOM... .
|
42
|
+
....8878+8ZONNNN.DDOZ$..DDNDOIMI7888=8OOO+....
|
43
|
+
..MO88O8O=8D88..8DOOO..DNN8$.Z88Z=O8Z=DIZ.. .
|
44
|
+
..DO8ZO8Z$D=D8..ZD8Z. .NDNDM.?O8OZ$?8$8Z8....
|
45
|
+
. ..DIDDD8OO78D. .Z8DD...,DND$..8OOD87D$$IM=...
|
46
|
+
...8DDO7OI$D$MO. .OND8,...NDD.. .M88I~N7DIDI..
|
47
|
+
...DZDMOZ$O88.....DDODM...DDZ.....NZ77O?Z?88...
|
48
|
+
...8D~D7D8ZO: ....DDNDDM..DDD7......=O8D$DDOD...
|
49
|
+
..DOD8888.... ..8NNDD,.ZDD87... ...DOZN+87... .
|
50
|
+
...... ......... ,8DND8Z.D$MOO...... ...,O.$$...
|
51
|
+
. ......... ....DNDDN+NDN8+8,... . ........
|
52
|
+
. . . ...DDDDD.MDN,7Z$. . ...
|
53
|
+
....DDND:.MDMM.~Z....... ..
|
54
|
+
......D8DDN..8DOZNIZ.........
|
55
|
+
... ... .7Z8DDDDDI,.NOD=O7.... ..
|
56
|
+
.. ..........:$$$NDNN87?MNI?IM..........
|
57
|
+
. ...........~D=?D$ODNNZD8=Z7=~++++++... .
|
58
|
+
..?????????8ZO7$Z8NNDN$O$?=++++++++....
|
59
|
+
...???????II$ZOZ7O+7OD$=OOI$=+++++++,...
|
60
|
+
...I+++++??I+D7O$8$?IM7:88=OO?++++++?..
|
61
|
+
...7++++++???$ZZZZZZ$Z$Z77~~+I+++++++:
|
62
|
+
.....?+++++??I++8DO8DON87+,+7O$?++++++++...
|
63
|
+
.....?+++++++??++?++?$ODZ$8$O$$Z=+++++++...
|
64
|
+
|
65
|
+
Introduction
|
66
|
+
------------
|
67
|
+
|
68
|
+
Pazuzu controls *applications*. An application consists of *workers*. Each worker has a name and a command line. Each worker may have multiple *instances* of itself running.
|
69
|
+
|
70
|
+
For example, a typical application may consist of:
|
71
|
+
|
72
|
+
* A Rails app, running under some web server like Thin or Unicorn.
|
73
|
+
* A WebSockets app listening on a socket.
|
74
|
+
* Some queue-processing daemons.
|
75
|
+
* Some maintenance jobs that run now and then.
|
76
|
+
|
77
|
+
Applications are configured through a simple text format:
|
78
|
+
|
79
|
+
<key>:<command line>
|
80
|
+
|
81
|
+
For example:
|
82
|
+
|
83
|
+
main: bundle exec unicorn -c config/unicorn.rb config.ru
|
84
|
+
queue_processor: bundle exec ruby app/queue_processor.rb
|
85
|
+
web_socket_server: node lib/server.js
|
86
|
+
|
87
|
+
Pazuzu will control the lifecycle of each worker. Main points:
|
88
|
+
|
89
|
+
* Workers can be started and stopped by issuing appropriate commands.
|
90
|
+
* Workers will be monitored and respawned if they crash.
|
91
|
+
* If the desired number of workers is changed, new worker instances will be spawned or terminated as needed.
|
92
|
+
* Recent output from workers is kept so that it can be viewed.
|
93
|
+
* If Pazuzu crashes, workers will continue to run, and will be reattached when Pazuzu is restarted.
|
94
|
+
|
95
|
+
Pazuzu leaves the following to external tools:
|
96
|
+
|
97
|
+
* Resource limiting. Use the Linux cgroups tools to limit CPU and memory usage.
|
98
|
+
* Scaling. Use external tools to monitor load, and invoke the `pazuzu` command to change the number of workers.
|
99
|
+
|
100
|
+
Installation
|
101
|
+
------------
|
102
|
+
|
103
|
+
gem install pazuzu
|
104
|
+
|
105
|
+
Requirements
|
106
|
+
------------
|
107
|
+
|
108
|
+
* Ruby 1.9.1 or later.
|
109
|
+
* Linux 2.6.24 or later with [cgroups](http://www.kernel.org/doc/Documentation/cgroups/) enabled in the kernel configuration.
|
110
|
+
* The [libcg](http://libcg.git.sourceforge.net/) binaries, which include `cgcreate` and `cgexec`.
|
111
|
+
|
112
|
+
Getting started
|
113
|
+
---------------
|
114
|
+
|
115
|
+
Create a minimal configuration `/etc/pazuzu/pazuzu.conf`:
|
116
|
+
|
117
|
+
applications:
|
118
|
+
myapp:
|
119
|
+
procfile: /srv/myapp
|
120
|
+
|
121
|
+
Create a minimal /srv/myapp/Procfile:
|
122
|
+
|
123
|
+
myworker: sleep 1h
|
124
|
+
|
125
|
+
Start Pazuzu (non-daemonized):
|
126
|
+
|
127
|
+
sudo pazuzud
|
128
|
+
|
129
|
+
Configuration file
|
130
|
+
------------------
|
131
|
+
|
132
|
+
`log_path`: Set the log file. Specify `syslog` to use syslog. Defaults to stderr.
|
133
|
+
|
134
|
+
`socket_path`: Where to create a socket for accepting commands. Defaults to `/var/run/pazuzud.socket`.
|
135
|
+
|
136
|
+
`include`: Include another configuration file or a number of files. May be either a single file name/glob pattern or an array of file names/glob patterns (eg., `/etc/pazuzu/conf.d/*.conf`). The included files's keys are merged into the current configuration in the order of inclusion.
|
137
|
+
|
138
|
+
`cgroups`: Has the following sub-keys:
|
139
|
+
|
140
|
+
* `hiearchy_root`: Root of hierarchy for all cgroups created. Defaults to `pazuzu`.
|
141
|
+
|
142
|
+
* `subsystems`: An array of cgroups subsystem to attach each cgroup to. Defaults to `memory`, `cpu`, `cpuacct` and `blkio` (essentially all subsystems at the time of writing).
|
143
|
+
|
144
|
+
* `fs_root`: Where the cgroups file system is mounted. Defaults to `/sys/fs/cgroup`, which may or may not be the default for your Linux distribution.
|
145
|
+
|
146
|
+
`applications`: This is where applications are listed. Each application has its own key. For example:
|
147
|
+
|
148
|
+
applications:
|
149
|
+
foo:
|
150
|
+
procfile: /srv/foo
|
151
|
+
|
152
|
+
Each application has the following sub-keys:
|
153
|
+
|
154
|
+
* `procfile` (*required*): The path to the procfile. If a directory, it's assumed that it contains a file named `Procfile`.
|
155
|
+
* `user`: User name or UID to run the process as. Defaults to the user that Pazuzu runs as.
|
156
|
+
* `group`: Group name or GID to run the process as. Defaults to the group that Pazuzu runs as.
|
157
|
+
* `workers`: This key allows per-worker overrides. Each worker has its own key, which is the name specified in the `Procfile`.
|
158
|
+
|
159
|
+
For example:
|
160
|
+
|
161
|
+
applications:
|
162
|
+
foo:
|
163
|
+
procfile: /srv/foo
|
164
|
+
workers:
|
165
|
+
bar:
|
166
|
+
num_instances: 2
|
167
|
+
|
168
|
+
Each worker has the following sub-keys:
|
169
|
+
|
170
|
+
* `command_line`: Override the worker's command line.
|
171
|
+
* `num_instances`: The number of instances to run. Defaults to 1.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
desc 'Bump version'
|
4
|
+
task :bump do
|
5
|
+
if `git status -uno -s --porcelain | wc -l`.to_i > 0
|
6
|
+
abort "You have uncommitted changed."
|
7
|
+
end
|
8
|
+
text = File.read('lib/pazuzu/version.rb')
|
9
|
+
if text =~ /VERSION = '(.*)'/
|
10
|
+
old_version = $1
|
11
|
+
version_parts = old_version.split('.')
|
12
|
+
version_parts[-1] = version_parts[-1].to_i + 1
|
13
|
+
new_version = version_parts.join('.')
|
14
|
+
text.gsub!(/VERSION = '(.*)'/, "VERSION = '#{new_version}'")
|
15
|
+
File.open('lib/pazuzu/version.rb', 'w') { |f| f << text }
|
16
|
+
(system("git add lib/pazuzu/version.rb") and
|
17
|
+
system("git commit -m 'Bump to #{new_version}.'")) or abort "Failed to commit."
|
18
|
+
else
|
19
|
+
abort "Could not find version number"
|
20
|
+
end
|
21
|
+
end
|
data/bin/pazuzu
ADDED
data/bin/pazuzud
ADDED
data/lib/pazuzu.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'optparse'
|
3
|
+
require 'timeout'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'yaml'
|
6
|
+
require 'singleton'
|
7
|
+
require 'logger'
|
8
|
+
require 'delegate'
|
9
|
+
require 'etc'
|
10
|
+
require 'thread'
|
11
|
+
require 'socket'
|
12
|
+
|
13
|
+
require 'statemachine'
|
14
|
+
require 'active_support/core_ext/hash'
|
15
|
+
require 'yajl/json_gem'
|
16
|
+
|
17
|
+
require 'pazuzu/utility/annotated_logger'
|
18
|
+
require 'pazuzu/utility/rate_limiter'
|
19
|
+
require 'pazuzu/utility/process_spawning'
|
20
|
+
require 'pazuzu/utility/runnable'
|
21
|
+
require 'pazuzu/utility/runnable_pool'
|
22
|
+
require 'pazuzu/utility/output_tailer'
|
23
|
+
|
24
|
+
require 'pazuzu/control/socket_server'
|
25
|
+
require 'pazuzu/control/socket_client'
|
26
|
+
require 'pazuzu/control/protocol'
|
27
|
+
|
28
|
+
require 'pazuzu/command_line/controller'
|
29
|
+
|
30
|
+
require 'pazuzu/supervisor'
|
31
|
+
require 'pazuzu/procfiles'
|
32
|
+
require 'pazuzu/application'
|
33
|
+
require 'pazuzu/instance'
|
34
|
+
require 'pazuzu/worker'
|
35
|
+
require 'pazuzu/supervisor_runner'
|
36
|
+
require 'pazuzu/version'
|
37
|
+
require 'pazuzu/cgroup'
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Pazuzu
|
2
|
+
|
3
|
+
class Application
|
4
|
+
|
5
|
+
include Utility::Runnable
|
6
|
+
|
7
|
+
def initialize(supervisor, name)
|
8
|
+
super()
|
9
|
+
@supervisor = supervisor
|
10
|
+
@name = name
|
11
|
+
@logger = Utility::AnnotatedLogger.new(supervisor.logger, qname)
|
12
|
+
@workers = Utility::RunnablePool.new
|
13
|
+
@mutex = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def configure!(procfile_path, configuration)
|
17
|
+
procfile_path = Procfiles.normalize_procfile_path(procfile_path)
|
18
|
+
|
19
|
+
root_path = File.dirname(procfile_path)
|
20
|
+
|
21
|
+
@user = configuration['user']
|
22
|
+
@group = configuration['group']
|
23
|
+
|
24
|
+
workers_config = configuration['workers'] || {}
|
25
|
+
|
26
|
+
leftover_workers = @workers.children.dup
|
27
|
+
|
28
|
+
procfile = YAML.load(File.open(procfile_path))
|
29
|
+
procfile = {} unless procfile.is_a?(Hash)
|
30
|
+
procfile.each do |name, command_line|
|
31
|
+
name = name.to_s
|
32
|
+
|
33
|
+
worker_config = workers_config[name] || {}
|
34
|
+
|
35
|
+
worker = @workers.children.select { |w| w.name == name }.first
|
36
|
+
if worker
|
37
|
+
leftover_workers.delete(worker)
|
38
|
+
else
|
39
|
+
@logger.info "Adding worker #{name}"
|
40
|
+
worker = Worker.new(self, name)
|
41
|
+
end
|
42
|
+
worker.configure!(root_path, command_line, worker_config)
|
43
|
+
@workers.register(worker)
|
44
|
+
end
|
45
|
+
|
46
|
+
leftover_workers.each do |worker|
|
47
|
+
@logger.info "Removing worker #{worker.name}"
|
48
|
+
@workers.unregister(worker)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def qname
|
53
|
+
@name
|
54
|
+
end
|
55
|
+
|
56
|
+
# Call to set up a forked process according to the application's
|
57
|
+
# configuration.
|
58
|
+
def setup_spawned_process!
|
59
|
+
Utility::ProcessSpawning.set_user_and_group!(@user, @group)
|
60
|
+
Utility::ProcessSpawning.prepare_child_process!
|
61
|
+
end
|
62
|
+
|
63
|
+
def workers
|
64
|
+
@workers.children
|
65
|
+
end
|
66
|
+
|
67
|
+
def log_entries
|
68
|
+
entries = @workers.children.map(&:log_entries)
|
69
|
+
entries.flatten!(1)
|
70
|
+
entries.sort_by! { |(source, time, message)| time }
|
71
|
+
entries
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :name
|
75
|
+
attr_reader :supervisor
|
76
|
+
attr_reader :user
|
77
|
+
attr_reader :group
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def on_starting
|
82
|
+
@logger.info "Starting"
|
83
|
+
@monitor_thread ||= Thread.start { monitor_workers }
|
84
|
+
@workers.start!
|
85
|
+
runnable_state.started!
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_started
|
89
|
+
@logger.info "Started"
|
90
|
+
end
|
91
|
+
|
92
|
+
def on_stopping
|
93
|
+
@logger.info "Stopping"
|
94
|
+
@workers.stop!
|
95
|
+
end
|
96
|
+
|
97
|
+
def monitor_workers
|
98
|
+
while [:starting, :running, :stopping].include?(run_state)
|
99
|
+
if runnable_state.state == :stopping
|
100
|
+
unless @workers.children.any? { |w| w.run_state == :running }
|
101
|
+
runnable_state.stopped!
|
102
|
+
end
|
103
|
+
end
|
104
|
+
sleep(1)
|
105
|
+
end
|
106
|
+
rescue Exception => e
|
107
|
+
@logger.error(e.message)
|
108
|
+
ensure
|
109
|
+
@monitor_thread = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Pazuzu
|
2
|
+
|
3
|
+
class Cgroup
|
4
|
+
|
5
|
+
class CgroupCreationFailed < Exception; end
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Are cgroups available?
|
9
|
+
def available?
|
10
|
+
File.exist?('/proc/cgroups')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(fs_root_path, path, subsystems)
|
15
|
+
@fs_root_path = fs_root_path
|
16
|
+
@path = path
|
17
|
+
@subsystems = subsystems
|
18
|
+
end
|
19
|
+
|
20
|
+
def mounted?
|
21
|
+
return @subsystems.any? { |subsystem|
|
22
|
+
Dir.glob(File.join(@fs_root_path, subsystem, @path, "cgroup.procs")).any? { |file_name|
|
23
|
+
File.exists?(file_name)
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def exec(command)
|
29
|
+
unless system("cgcreate -g #{@subsystems.join(',')}:#{@path}")
|
30
|
+
raise CgroupCreationFailed, "Could not create cgroup hiearchy #{@path}"
|
31
|
+
end
|
32
|
+
command = "cgexec -g #{@subsystems.join(',')}:#{@path} #{command}"
|
33
|
+
return Process.exec(command)
|
34
|
+
end
|
35
|
+
|
36
|
+
def pids
|
37
|
+
pids = pids_including_children
|
38
|
+
pids.reject { |pid| pids.include?(parent_pid_for(pid)) }
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :path
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def pids_including_children
|
46
|
+
return @subsystems.flat_map { |subsystem|
|
47
|
+
Dir.glob(File.join(@fs_root_path, subsystem, @path, "cgroup.procs")).flat_map { |file_name|
|
48
|
+
begin
|
49
|
+
File.read(file_name).split("\n").map { |s| Integer(s) }
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
}
|
54
|
+
}.compact.tap(&:uniq!)
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent_pid_for(pid)
|
58
|
+
begin
|
59
|
+
File.readlines("/proc/#{pid}/status").each do |line|
|
60
|
+
return $1.to_i if line =~ /^PPid:\s*(\d+)/i
|
61
|
+
end
|
62
|
+
rescue Errno::ENOENT
|
63
|
+
end
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def subsystem_path(subsystem)
|
68
|
+
File.join(@fs_root_path, subsystem, @path)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|