lxc 0.2.13 → 0.3.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.
- data/lib/lxc.rb +12 -62
- data/lib/lxc/config.rb +1 -1
- data/lib/lxc/container.rb +35 -2
- data/lib/lxc/runners/shell.rb +3 -3
- data/lib/lxc/runners/ssh.rb +94 -0
- data/lib/lxc/version.rb +1 -1
- data/spec/lxc/config_spec.rb +1 -1
- data/spec/lxc_spec.rb +8 -17
- metadata +3 -8
data/lib/lxc.rb
CHANGED
@@ -14,34 +14,17 @@ class LXC
|
|
14
14
|
autoload :Container, 'lxc/container'
|
15
15
|
autoload :Runner, 'lxc/runner'
|
16
16
|
|
17
|
-
#
|
17
|
+
# The runner we will use to execute all LXC commands.
|
18
18
|
#
|
19
|
-
# @overload
|
20
|
-
# Sets
|
21
|
-
# @param [
|
19
|
+
# @overload runner=(value)
|
20
|
+
# Sets the runner to use.
|
21
|
+
# @param [LXC::Runner] value
|
22
22
|
#
|
23
|
-
# @overload
|
24
|
-
# Gets
|
23
|
+
# @overload runner
|
24
|
+
# Gets the runner we are using, if any.
|
25
25
|
#
|
26
|
-
# @return [
|
27
|
-
|
28
|
-
attr_accessor :use_sudo
|
29
|
-
|
30
|
-
# Controls if executed commands run locally or remotely via a Net::SSH
|
31
|
-
# Session.
|
32
|
-
#
|
33
|
-
# @overload use_ssh=(value)
|
34
|
-
# Sets if all executed commands should be run locally or remotely.
|
35
|
-
# To force commands to run locally, assign a value of nil (default).
|
36
|
-
# To force commands to run remotely, assign a valid, active, Net::SSH
|
37
|
-
# Session.
|
38
|
-
#
|
39
|
-
# @overload use_ssh
|
40
|
-
# Gets if we are executing commands locally or remotely.
|
41
|
-
#
|
42
|
-
# @return [Net::SSH::Connection::Session] Returns nil if disabled; otherwise
|
43
|
-
# returns the assigned Net::SSH Session object.
|
44
|
-
attr_accessor :use_ssh
|
26
|
+
# @return [LXC::Runner] Returns the instance of the runner we are using.
|
27
|
+
attr_accessor :runner
|
45
28
|
|
46
29
|
# RegEx pattern for extracting the LXC Version from the "lxc-version" command
|
47
30
|
# output.
|
@@ -54,8 +37,7 @@ class LXC
|
|
54
37
|
# execute all commands remotely via an SSH connection.
|
55
38
|
def initialize(options={})
|
56
39
|
@ui = (options[:ui] || ZTK::UI.new)
|
57
|
-
@
|
58
|
-
@use_ssh = (options[:use_ssh] || nil)
|
40
|
+
@runner = (options[:runner] || LXC::Runner::Shell.new(:ui => @ui))
|
59
41
|
end
|
60
42
|
|
61
43
|
# LXC configuration class
|
@@ -157,47 +139,15 @@ class LXC
|
|
157
139
|
# @param [Array] args Additional command-line arguments.
|
158
140
|
# @return [Array<String>] Stripped output text of the executed command.
|
159
141
|
def exec(*args)
|
160
|
-
|
161
|
-
|
162
|
-
arguments = Array.new
|
163
|
-
arguments << %(sudo) if (@use_sudo == true)
|
164
|
-
arguments << command
|
165
|
-
arguments << args
|
166
|
-
arguments = arguments.flatten.compact.join(' ')
|
167
|
-
|
168
|
-
output = Array.new
|
169
|
-
|
170
|
-
if @use_ssh.nil?
|
171
|
-
begin
|
172
|
-
::ZTK::PTY.spawn(arguments) do |reader, writer, pid|
|
173
|
-
while (buffer = reader.readpartial(1024))
|
174
|
-
output << buffer
|
175
|
-
end
|
176
|
-
end
|
177
|
-
rescue EOFError
|
178
|
-
# NOOP
|
179
|
-
end
|
180
|
-
else
|
181
|
-
if @use_ssh.is_a?(ZTK::SSH)
|
182
|
-
output << @use_ssh.exec(arguments, :silence => true, :ignore_exit_status => true).output
|
183
|
-
else
|
184
|
-
if @use_ssh.respond_to?(:exec!)
|
185
|
-
output << @use_ssh.exec!(arguments)
|
186
|
-
else
|
187
|
-
raise LXCError, "The object you assigned to use_ssh does not respond to #exec!"
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
output.join.strip
|
142
|
+
@runner.exec(*args)
|
193
143
|
end
|
194
144
|
|
195
145
|
# Provides a concise string representation of the class
|
196
146
|
# @return [String]
|
197
147
|
def inspect
|
198
148
|
tags = Array.new
|
199
|
-
tags << "
|
200
|
-
tags <<
|
149
|
+
tags << "version=#{self.version.inspect}"
|
150
|
+
tags << "runner=#{@runner.inspect}" if @runner
|
201
151
|
tags = tags.join(' ')
|
202
152
|
|
203
153
|
"#<LXC #{tags}>"
|
data/lib/lxc/config.rb
CHANGED
data/lib/lxc/container.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'timeout'
|
2
|
-
|
3
1
|
class LXC
|
4
2
|
|
5
3
|
# Container Error Class
|
@@ -9,6 +7,8 @@ class LXC
|
|
9
7
|
#
|
10
8
|
# @author Zachary Patten <zachary AT jovelabs DOT com>
|
11
9
|
class Container
|
10
|
+
require 'timeout'
|
11
|
+
require 'tempfile'
|
12
12
|
|
13
13
|
# An array containing the valid container states extracted from the LXC
|
14
14
|
# c-source code.
|
@@ -244,6 +244,39 @@ class LXC
|
|
244
244
|
self.exec("lxc-attach", *args)
|
245
245
|
end
|
246
246
|
|
247
|
+
# Bootstrap a container
|
248
|
+
#
|
249
|
+
# Renders the supplied text blob inside a container as a script and executes
|
250
|
+
# it via lxc-attach. The container must already be running.
|
251
|
+
#
|
252
|
+
# @see lxc-attach
|
253
|
+
#
|
254
|
+
# @param [String] content The content to render in the container and
|
255
|
+
# execute. This is generally a bash script of some sort for example.
|
256
|
+
# @return [String] The output of *lxc-attach*.
|
257
|
+
def bootstrap(content)
|
258
|
+
output = nil
|
259
|
+
|
260
|
+
ZTK::RescueRetry.try(:tries => 5, :on => ContainerError) do
|
261
|
+
tempfile = Tempfile.new("bootstrap")
|
262
|
+
bootstrap_tempfile = File.join("/", "tmp", File.basename(tempfile.path))
|
263
|
+
|
264
|
+
self.exec(<<-SCRIPT)
|
265
|
+
cat <<-EOF | tee #{bootstrap_tempfile}
|
266
|
+
#{content}
|
267
|
+
EOF
|
268
|
+
SCRIPT
|
269
|
+
|
270
|
+
output = self.lxc.attach(%(-- /bin/bash #{bootstrap_tempfile}))
|
271
|
+
|
272
|
+
if !(output =~ /#{bootstrap_tempfile}: No such file or directory/).nil?
|
273
|
+
raise ContainerError, "We could not find the bootstrap file!"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
output
|
278
|
+
end
|
279
|
+
|
247
280
|
# Launch a console for the container
|
248
281
|
#
|
249
282
|
# @see lxc-console
|
data/lib/lxc/runners/shell.rb
CHANGED
@@ -25,8 +25,8 @@ class LXC
|
|
25
25
|
def initialize(options={})
|
26
26
|
@hostname = Socket.gethostname.split('.').first.strip
|
27
27
|
|
28
|
-
@ui = (options[:ui]
|
29
|
-
@use_sudo = (options[:use_sudo] ||
|
28
|
+
@ui = (options[:ui] || ZTK::UI.new)
|
29
|
+
@use_sudo = (options[:use_sudo] || true)
|
30
30
|
end
|
31
31
|
|
32
32
|
# Linux container command execution wrapper
|
@@ -62,7 +62,7 @@ class LXC
|
|
62
62
|
# NOOP
|
63
63
|
end
|
64
64
|
|
65
|
-
output.join
|
65
|
+
output.join.strip
|
66
66
|
end
|
67
67
|
|
68
68
|
# Provides a concise string representation of the class
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class LXC
|
2
|
+
class Runner
|
3
|
+
|
4
|
+
class SSHError < RunnerError; end
|
5
|
+
|
6
|
+
class SSH
|
7
|
+
require 'socket'
|
8
|
+
|
9
|
+
# Controls if sudo is prefixed on all executed commands.
|
10
|
+
#
|
11
|
+
# @overload use_sudo=(value)
|
12
|
+
# Sets if all executed commands should be prefixed with sudo.
|
13
|
+
# @param [Boolean] value
|
14
|
+
#
|
15
|
+
# @overload use_sudo
|
16
|
+
# Gets if we are prefixing all executed commands with sudo.
|
17
|
+
#
|
18
|
+
# @return [Boolean] Returns true if we are prefixing commands with "sudo";
|
19
|
+
# otherwise false.
|
20
|
+
attr_accessor :use_sudo
|
21
|
+
|
22
|
+
# @param [Hash] options Options hash.
|
23
|
+
# @option options [Boolean] :use_sudo (false) Whether or not to prefix all
|
24
|
+
# commands with 'sudo'.
|
25
|
+
def initialize(options={})
|
26
|
+
@ui = (options[:ui] || ZTK::UI.new)
|
27
|
+
@use_sudo = (options[:use_sudo] || true)
|
28
|
+
@ssh = (options[:ssh])
|
29
|
+
|
30
|
+
@ssh.nil? and raise SSHError, "You must supply a ZTK::SSH or Net::SSH instance!"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Linux container command execution wrapper
|
34
|
+
#
|
35
|
+
# Runs the supplied LXC command. The first element in the "args" splat is the
|
36
|
+
# command to be execute, the rest of the elements are treated as command line
|
37
|
+
# arguments.
|
38
|
+
#
|
39
|
+
# If use_sudo is true then all commands will be prefix with "sudo".
|
40
|
+
# If use_ssh is non-nil then all commands will be execute via the assigned
|
41
|
+
# Net::SSH Session.
|
42
|
+
#
|
43
|
+
# @param [Array] args Additional command-line arguments.
|
44
|
+
# @return [Array<String>] Stripped output text of the executed command.
|
45
|
+
def exec(*args)
|
46
|
+
command = args.shift
|
47
|
+
|
48
|
+
arguments = Array.new
|
49
|
+
arguments << %(sudo) if (@use_sudo == true)
|
50
|
+
arguments << command
|
51
|
+
arguments << args
|
52
|
+
arguments = arguments.flatten.compact.join(' ')
|
53
|
+
|
54
|
+
output = Array.new
|
55
|
+
|
56
|
+
if @ssh.is_a?(ZTK::SSH)
|
57
|
+
output << @ssh.exec(arguments, :silence => true, :ignore_exit_status => true).output
|
58
|
+
else
|
59
|
+
if @ssh.respond_to?(:exec!)
|
60
|
+
output << @ssh.exec!(arguments)
|
61
|
+
else
|
62
|
+
raise SSHError, "The object you assigned to ssh does not respond to #exec!"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
output.join.strip
|
67
|
+
end
|
68
|
+
|
69
|
+
# Provides a concise string representation of the class
|
70
|
+
# @return [String]
|
71
|
+
def inspect
|
72
|
+
if @hostname.nil?
|
73
|
+
if @ssh.is_a?(ZTK::SSH)
|
74
|
+
@hostname ||= @ssh.exec(%(hostname -s)).output.strip
|
75
|
+
else
|
76
|
+
if @ssh.respond_to?(:exec!)
|
77
|
+
@hostname ||= @ssh.exec!(%(hostname -s)).strip
|
78
|
+
else
|
79
|
+
raise SSHError, "The object you assigned to ssh does not respond to #exec!"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
tags = Array.new
|
85
|
+
tags << "host=#{@hostname.inspect}"
|
86
|
+
tags << "use_sudo=#{@use_sudo.inspect}"
|
87
|
+
tags = tags.join(' ')
|
88
|
+
|
89
|
+
"#<#{self.class} #{tags}>"
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/lxc/version.rb
CHANGED
data/spec/lxc/config_spec.rb
CHANGED
@@ -24,7 +24,7 @@ describe LXC::Config do
|
|
24
24
|
subject {
|
25
25
|
config_file = File.expand_path(File.join(File.dirname(__FILE__), '..', 'support', 'fixtures', 'test-container'))
|
26
26
|
|
27
|
-
@lxc = LXC.new
|
27
|
+
@lxc = LXC.new
|
28
28
|
lxc_config = LXC::Config.new(@lxc, config_file)
|
29
29
|
lxc_config.load
|
30
30
|
|
data/spec/lxc_spec.rb
CHANGED
@@ -29,18 +29,6 @@ describe LXC do
|
|
29
29
|
subject.should be_an_instance_of LXC
|
30
30
|
end
|
31
31
|
|
32
|
-
describe "defaults" do
|
33
|
-
|
34
|
-
it "should have use_sudo set to false" do
|
35
|
-
subject.use_sudo.should == false
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should have use_ssh set to nil" do
|
39
|
-
subject.use_ssh.should == nil
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
32
|
end
|
45
33
|
|
46
34
|
describe "methods" do
|
@@ -195,17 +183,20 @@ describe LXC do
|
|
195
183
|
end
|
196
184
|
|
197
185
|
context "against remote host" do
|
198
|
-
|
199
|
-
|
186
|
+
|
187
|
+
subject {
|
188
|
+
connection = ::ZTK::SSH.new(
|
200
189
|
:host_name => "127.0.0.1",
|
201
190
|
:user => ENV['USER'],
|
202
191
|
:keys => File.join(ENV['HOME'], '.ssh', 'id_rsa'),
|
203
192
|
:keys_only => true
|
204
|
-
)
|
205
|
-
|
193
|
+
)
|
194
|
+
runner = ::LXC::Runner::SSH.new(:ssh => connection.ssh)
|
195
|
+
|
196
|
+
LXC.new(:runner => runner)
|
197
|
+
}
|
206
198
|
|
207
199
|
it "should exec the supplied LXC command" do
|
208
|
-
subject.use_ssh = @ssh_connection
|
209
200
|
subject.exec("version").should be_kind_of(String)
|
210
201
|
end
|
211
202
|
end if !ENV['CI'] && !ENV['TRAVIS']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lxc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ztk
|
@@ -163,6 +163,7 @@ files:
|
|
163
163
|
- lib/lxc/container.rb
|
164
164
|
- lib/lxc/runner.rb
|
165
165
|
- lib/lxc/runners/shell.rb
|
166
|
+
- lib/lxc/runners/ssh.rb
|
166
167
|
- lib/lxc/version.rb
|
167
168
|
- lxc.gemspec
|
168
169
|
- spec/lxc/config_spec.rb
|
@@ -216,18 +217,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
216
217
|
- - ! '>='
|
217
218
|
- !ruby/object:Gem::Version
|
218
219
|
version: '0'
|
219
|
-
segments:
|
220
|
-
- 0
|
221
|
-
hash: 2981418491518284885
|
222
220
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
223
221
|
none: false
|
224
222
|
requirements:
|
225
223
|
- - ! '>='
|
226
224
|
- !ruby/object:Gem::Version
|
227
225
|
version: '0'
|
228
|
-
segments:
|
229
|
-
- 0
|
230
|
-
hash: 2981418491518284885
|
231
226
|
requirements: []
|
232
227
|
rubyforge_project:
|
233
228
|
rubygems_version: 1.8.25
|