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 CHANGED
@@ -14,34 +14,17 @@ class LXC
14
14
  autoload :Container, 'lxc/container'
15
15
  autoload :Runner, 'lxc/runner'
16
16
 
17
- # Controls if sudo is prefixed on all executed commands.
17
+ # The runner we will use to execute all LXC commands.
18
18
  #
19
- # @overload use_sudo=(value)
20
- # Sets if all executed commands should be prefixed with sudo.
21
- # @param [Boolean] value
19
+ # @overload runner=(value)
20
+ # Sets the runner to use.
21
+ # @param [LXC::Runner] value
22
22
  #
23
- # @overload use_sudo
24
- # Gets if we are prefixing all executed commands with sudo.
23
+ # @overload runner
24
+ # Gets the runner we are using, if any.
25
25
  #
26
- # @return [Boolean] Returns true if we are prefixing commands with "sudo";
27
- # otherwise false.
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
- @use_sudo = (options[:use_sudo] || false)
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
- command = args.shift
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 << "use_sudo=#{@use_sudo}" if @use_sudo
200
- tags << (@use_ssh.nil? ? "use_ssh=false" : "use_ssh=true")
149
+ tags << "version=#{self.version.inspect}"
150
+ tags << "runner=#{@runner.inspect}" if @runner
201
151
  tags = tags.join(' ')
202
152
 
203
153
  "#<LXC #{tags}>"
@@ -36,7 +36,7 @@ class LXC
36
36
  #
37
37
  # @return [Hash] LXC configuration hash.
38
38
  def save
39
- use_sudo = (@lxc.use_sudo ? 'sudo ' : nil)
39
+ use_sudo = (@lxc.runner.use_sudo ? 'sudo ' : nil)
40
40
 
41
41
  script = Array.new
42
42
  script << "cat <<EOF | #{use_sudo}tee #{@filename}"
@@ -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
@@ -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] || ZTK::UI.new)
29
- @use_sudo = (options[:use_sudo] || false)
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
@@ -2,7 +2,7 @@ class LXC
2
2
 
3
3
  unless const_defined?(:VERSION)
4
4
  # LXC Gem Version
5
- VERSION = "0.2.13"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
 
8
8
  end
@@ -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(:use_sudo => true)
27
+ @lxc = LXC.new
28
28
  lxc_config = LXC::Config.new(@lxc, config_file)
29
29
  lxc_config.load
30
30
 
@@ -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
- before(:each) do
199
- @ssh_connection = ::ZTK::SSH.new(
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
- ).ssh
205
- end
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.2.13
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-22 00:00:00.000000000 Z
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