lxc 0.2.13 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|