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 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