hrr_rb_lxns 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8243b5243363dd383204313c4487478786834e46ff9a3c1be7f90b2c5f77052
4
- data.tar.gz: daa322824dc8a8c75a80213d37739b44e223a09647d73502c5b448b014629df1
3
+ metadata.gz: f96ad9d7f1439e815c23aebf272ff8ca0984dba7ec9775e22483d33a390e82b1
4
+ data.tar.gz: 0eba5185a5c6c23660b69acd7982b5982830a50e2dad726b09c1f89f93325780
5
5
  SHA512:
6
- metadata.gz: 948f4793805ee19b20cd5da1fc1f9acff00c065829708bc9f1fb26e947917214e480b6ad8c86d955863dcb0e10a5413f335fa9270dcdf2c816f6ba0d4d2e12a6
7
- data.tar.gz: 3a74b885cff6c12dcd179b6ee697d4e0da73f078f6dab6e3de8358e913ef0caa556ad104d05ff188eec848b3e804862fcb818e9da68cd7b0d64c59697347825b
6
+ metadata.gz: af3f529c576999c3f11371b0ea4ffaf59ad62f0500185a3b238026d41744251732f24d1123590f981d9eeb260188599358b626fd634d69f25a13aafe5cfbb694
7
+ data.tar.gz: d28a267db5871149c88a145aef192612d8f007826670ded888b5a96836593211431cf4d038e6fb314427ccefdc3dba7dd5b3439b14374f36a6d813dad201a0da
data/README.md CHANGED
@@ -45,6 +45,39 @@ File.readlink "/proc/self/ns/uts" # => uts:[xxx]
45
45
  File.readlink "/proc/self/ns/mnt" # => mnt:[yyy]
46
46
  ```
47
47
 
48
+ HrrRbLxns.unshare supports creating persistent namespaces files by bind-mount. The files are specified in an options hash. The keys which are available in the hash for each namespace are `:mount`, `:uts`, `:ipc`, `:network`, `:pid`, `:user`, `:cgroup`, and `:time`.
49
+ Note that files that namespaces are bind-mounted must exist. The library does just bind-mount, not create the files. And the files and their mount information are kept after the caller process is finished.
50
+ When unsharing pid namespace, the namespace file should be bind-mounted against the caller's child process. For this case, `:fork` option is supported.
51
+
52
+ ```ruby
53
+ File.readlink "/proc/self/ns/uts" # => uts:[aaa]
54
+ # Prepare an options hash to specify a file that namespaces are bind-mounted
55
+ options = {:uts => "/path/to/myns/uts"}
56
+ HrrRbLxns.unshare HrrRbLxns::NEWUTS, options # => 0
57
+ File.readlink "/proc/self/ns/uts" # => uts:[xxx]
58
+ File.stat(options[:uts]).ino # => xxx
59
+
60
+ # For mount namespace, the parent directory's propagation needs to be private
61
+ FileUtils.mkdir "/path/to/myns"
62
+ HrrRbMount.bind "/path/to/myns" "/path/to/myns"
63
+ HrrRbMount.make_private "/path/to/myns"
64
+ FileUtils.touch "/path/to/myns/mnt"
65
+ options = {:mount => "/path/to/myns/mnt"}
66
+ HrrRbLxns.unshare HrrRbLxns::NEWNS, options # => 0
67
+
68
+ # For pid namespace, :fork option is available
69
+ options = {:pid => "/path/to/myns/pid", :fork => true}
70
+ # .unshare method with :fork option works like Kernel.#fork after unshare(2)
71
+ if pid = HrrRbLxns.unshare HrrRbLxns::NEWPID, options
72
+ # In parent, .unshare returns the child process's PID (In this case, it is 1 because unsharing PID namespace)
73
+ # Do something
74
+ Process.waitpid pid
75
+ else
76
+ # In child, .unshare returns nil
77
+ # Do something
78
+ end
79
+ ```
80
+
48
81
  ### Setns
49
82
 
50
83
  HrrRbLxns.setns method wraps around setns(2) system call. The system call associate the caller process's namespace to an existing one, which is disassociated by some other process.
data/hrr_rb_lxns.gemspec CHANGED
@@ -21,4 +21,6 @@ Gem::Specification.new do |spec|
21
21
  end
22
22
  spec.require_paths = ["lib"]
23
23
  spec.extensions = ["ext/hrr_rb_lxns/extconf.rb"]
24
+
25
+ spec.add_dependency "hrr_rb_mount", ">= 0.3.0"
24
26
  end
@@ -1,3 +1,3 @@
1
1
  module HrrRbLxns
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/hrr_rb_lxns.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "hrr_rb_lxns/version"
2
2
  require "hrr_rb_lxns/hrr_rb_lxns"
3
+ require "hrr_rb_mount"
3
4
 
4
5
  # Utilities working with Linux namespaces for CRuby.
5
6
  module HrrRbLxns
@@ -33,14 +34,29 @@ module HrrRbLxns
33
34
  # "U" : NEWUSER <br>
34
35
  # "C" : NEWCGROUP <br>
35
36
  # "T" : NEWTIME <br>
36
- # @param options [Hash] For future use.
37
- # @return [Integer] 0.
37
+ # @param options [Hash] Optional arguments.
38
+ # @option options [String] :mount A persistent mount namespace to be created by bind mount.
39
+ # @option options [String] :uts A persistent uts namespace to be created by bind mount.
40
+ # @option options [String] :ipc A persistent ipc namespace to be created by bind mount.
41
+ # @option options [String] :network A persistent network namespace to be created by bind mount.
42
+ # @option options [String] :pid A persistent pid namespace to be created by bind mount.
43
+ # @option options [String] :user A persistent user namespace to be created by bind mount.
44
+ # @option options [String] :cgroup A persistent cgroup namespace to be created by bind mount.
45
+ # @option options [String] :time A persistent time namespace to be created by bind mount.
46
+ # @option options [Boolean] :fork If specified, the caller process forks after unshare.
47
+ # @return [Integer, nil] Usually 0. If :fork is specified in options, then PID of the child process in parent, nil in child (as same as Kernel.#fork).
38
48
  # @raise [ArgumentError] When given flags argument is not appropriate.
39
49
  # @raise [Errno::EXXX] In case unshare(2) system call failed.
40
-
41
50
  def self.unshare flags, options={}
42
51
  _flags = interpret_flags flags
43
- __unshare__ _flags
52
+ bind_ns_files_from_child(_flags, options) do
53
+ if fork? options
54
+ __unshare__ _flags
55
+ fork
56
+ else
57
+ __unshare__ _flags
58
+ end
59
+ end
44
60
  end
45
61
 
46
62
  # A wrapper around setns(2) system call.
@@ -120,6 +136,88 @@ module HrrRbLxns
120
136
  end
121
137
  end
122
138
 
139
+ def self.fork? options
140
+ options[:fork]
141
+ end
142
+
143
+ def self.bind_ns_files? options
144
+ list = Array.new
145
+ list.push :ipc if const_defined?(:NEWIPC)
146
+ list.push :mount if const_defined?(:NEWNS)
147
+ list.push :network if const_defined?(:NEWNET)
148
+ list.push :pid if const_defined?(:NEWPID)
149
+ list.push :uts if const_defined?(:NEWUTS)
150
+ list.push :user if const_defined?(:NEWUSER)
151
+ list.push :cgroup if const_defined?(:NEWCGROUP)
152
+ list.push :time if const_defined?(:NEWTIME)
153
+ (list & options.keys).empty?.!
154
+ end
155
+
156
+ # In some cases, namespace files need to be created by an external process.
157
+ # Thus, this method calls fork and the child process creates the namespace files.
158
+ def self.bind_ns_files_from_child flags, options
159
+ if bind_ns_files? options
160
+ pid_to_bind = Process.pid
161
+ pid = nil
162
+ begin
163
+ io_r, io_w = IO.pipe
164
+ if pid = fork
165
+ ret = yield
166
+ io_w.write "1"
167
+ io_w.close
168
+ if pid_to_bind == Process.pid
169
+ _, status = Process.waitpid2 pid
170
+ raise Marshal.load(io_r.read) if status.exitstatus != 0
171
+ end
172
+ ret
173
+ else
174
+ begin
175
+ exit_status = true
176
+ io_r.read 1
177
+ bind_ns_files flags, options, pid_to_bind
178
+ rescue Exception => e
179
+ exit_status = false
180
+ io_w.write Marshal.dump(e)
181
+ ensure
182
+ exit! exit_status
183
+ end
184
+ end
185
+ ensure
186
+ io_w.write "1" rescue nil # just in case getting an error before io_w.write
187
+ io_w.close rescue nil
188
+ io_r.close rescue nil
189
+ if pid_to_bind == Process.pid
190
+ begin
191
+ Process.waitpid pid
192
+ rescue Errno::ECHILD
193
+ end
194
+ end
195
+ end
196
+ else
197
+ yield
198
+ end
199
+ end
200
+
201
+ def self.bind_ns_files flags, options, pid
202
+ list = Array.new
203
+ list.push ["ipc", NEWIPC, :ipc ] if const_defined?(:NEWIPC)
204
+ list.push ["mnt", NEWNS, :mount ] if const_defined?(:NEWNS)
205
+ list.push ["net", NEWNET, :network] if const_defined?(:NEWNET)
206
+ list.push ["pid", NEWPID, :pid ] if const_defined?(:NEWPID)
207
+ if File.exist? "/proc/#{pid}/ns/pid_for_children"
208
+ list.last[0] = "pid_for_children"
209
+ end
210
+ list.push ["uts", NEWUTS, :uts ] if const_defined?(:NEWUTS)
211
+ list.push ["user", NEWUSER, :user ] if const_defined?(:NEWUSER)
212
+ list.push ["cgroup", NEWCGROUP, :cgroup ] if const_defined?(:NEWCGROUP)
213
+ list.push ["time", NEWTIME, :time ] if const_defined?(:NEWTIME)
214
+ list.each do |name, flag, key|
215
+ if (flags & flag).zero?.! && options[key]
216
+ HrrRbMount.bind "/proc/#{pid}/ns/#{name}", options[key]
217
+ end
218
+ end
219
+ end
220
+
123
221
  def self.do_setns nstype_file_h
124
222
  nstype_file_h.each do |nstype, file|
125
223
  File.open(file, File::RDONLY) do |f|
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hrr_rb_lxns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hirura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-02 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: hrr_rb_mount
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.0
13
27
  description: Utilities working with Linux namespaces for CRuby.
14
28
  email:
15
29
  - hirura@gmail.com