lxc-ruby 0.2.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +1 -0
- data/Gemfile +1 -1
- data/README.md +13 -16
- data/Vagrantfile +111 -0
- data/lib/lxc/configuration.rb +17 -2
- data/lib/lxc/container.rb +51 -45
- data/lib/lxc/shell.rb +7 -4
- data/lib/lxc/status.rb +22 -0
- data/lib/lxc/version.rb +1 -1
- data/lib/lxc.rb +60 -51
- data/{lxc.gemspec → lxc-ruby.gemspec} +4 -2
- data/spec/configuration_spec.rb +9 -9
- data/spec/container_spec.rb +80 -39
- data/spec/lxc_spec.rb +74 -63
- data/spec/spec_helper.rb +10 -1
- data/spec/status_spec.rb +33 -0
- metadata +33 -29
- data/lib/lxc/errors.rb +0 -5
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9b048cb271bb43ee64cf3759aa1916899b9c85e5
|
4
|
+
data.tar.gz: c91c3b7c6e0998b64eccf7e81f033781d997ff51
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fc5eddbca427353c4f33dbcab6f559949dddd2472239488badebc54eae7d8ed831462832ba7e7b67ec8230fc8e7841094d549d418a55814448d05fd08ed16217
|
7
|
+
data.tar.gz: de0f0ad1dea5a915b1ceddc781aaf488e1b19194ef4143e6604bb7d5c901cf67231c8355415a791e91245f4d12ad945a833ba34a019fe9cf07f9e286a696fca1
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
data/README.md
CHANGED
@@ -1,23 +1,17 @@
|
|
1
|
-
# LXC Ruby Wrapper
|
1
|
+
# LXC Ruby Wrapper [![Build Status](https://secure.travis-ci.org/sosedoff/lxc-ruby.png?branch=master)](http://travis-ci.org/sosedoff/lxc-ruby)
|
2
2
|
|
3
|
-
Ruby
|
4
|
-
|
5
|
-
## Build status
|
6
|
-
|
7
|
-
This library uses Travis-CI service for automated tests.
|
8
|
-
|
9
|
-
[![Build Status](https://secure.travis-ci.org/sosedoff/lxc-ruby.png?branch=master)](http://travis-ci.org/sosedoff/lxc-ruby)
|
3
|
+
Ruby library to integrate with [Linux Containers](http://lxc.sourceforge.net/) CLI tools
|
10
4
|
|
11
5
|
## Requirements
|
12
6
|
|
13
7
|
Supported LXC versions:
|
14
8
|
|
15
9
|
- 0.7.5
|
16
|
-
- 0.8.0
|
17
|
-
- 0.8.0-rc2 - in works
|
10
|
+
- 0.8.0
|
18
11
|
|
19
|
-
For testing purposes you can use [Vagrant](http://vagrantup.com/)
|
20
|
-
was tested on Ubuntu 11.
|
12
|
+
For testing purposes you can use [Vagrant](http://vagrantup.com/) with [VirtualBox](https://www.virtualbox.org/).
|
13
|
+
Most of the functionality was tested on 64-bit Ubuntu 11.10 and 12.04. Recommended version is 12.04.
|
14
|
+
Additional boxes could be found [here](http://www.vagrantbox.es/).
|
21
15
|
|
22
16
|
## Installation
|
23
17
|
|
@@ -64,10 +58,13 @@ Container instance is a simple abstaction for lxc's container tools:
|
|
64
58
|
c = LXC.container('foo')
|
65
59
|
|
66
60
|
# Get current status of container
|
67
|
-
c.
|
61
|
+
c.state # => 'running'
|
62
|
+
c.pid # => 1234
|
63
|
+
c.status # => <LXC::Status @state='running' @pid=123456>
|
68
64
|
|
69
65
|
# Check if container exists?
|
70
|
-
#
|
66
|
+
#
|
67
|
+
# This is needed since lxc does not raise any errors if container is
|
71
68
|
# not present in the system, and returns the same result as if container
|
72
69
|
# is actually stopped
|
73
70
|
c.exists? # => true
|
@@ -78,8 +75,8 @@ c.stopped? # => false
|
|
78
75
|
c.frozen? # => false
|
79
76
|
|
80
77
|
# Start and stop containers
|
81
|
-
c.start
|
82
|
-
c.stop
|
78
|
+
c.start # will be started in daemonized mode
|
79
|
+
c.stop
|
83
80
|
|
84
81
|
# Free and unfreeze (also returns current status)
|
85
82
|
c.freeze
|
data/Vagrantfile
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant.configure("2") do |config|
|
5
|
+
# All Vagrant configuration is done here. The most common configuration
|
6
|
+
# options are documented and commented below. For a complete reference,
|
7
|
+
# please see the online documentation at vagrantup.com.
|
8
|
+
|
9
|
+
# Every Vagrant virtual environment requires a box to build off of.
|
10
|
+
config.vm.box = "precise64"
|
11
|
+
|
12
|
+
# The url from where the 'config.vm.box' box will be fetched if it
|
13
|
+
# doesn't already exist on the user's system.
|
14
|
+
config.vm.box_url = "http://files.vagrantup.com/precise64.box"
|
15
|
+
|
16
|
+
# Create a forwarded port mapping which allows access to a specific port
|
17
|
+
# within the machine from a port on the host machine. In the example below,
|
18
|
+
# accessing "localhost:8080" will access port 80 on the guest machine.
|
19
|
+
# config.vm.network :forwarded_port, guest: 80, host: 8080
|
20
|
+
|
21
|
+
# Create a private network, which allows host-only access to the machine
|
22
|
+
# using a specific IP.
|
23
|
+
config.vm.network :private_network, ip: "192.168.33.10"
|
24
|
+
|
25
|
+
# Create a public network, which generally matched to bridged network.
|
26
|
+
# Bridged networks make the machine appear as another physical device on
|
27
|
+
# your network.
|
28
|
+
# config.vm.network :public_network
|
29
|
+
|
30
|
+
# Share an additional folder to the guest VM. The first argument is
|
31
|
+
# the path on the host to the actual folder. The second argument is
|
32
|
+
# the path on the guest to mount the folder. And the optional third
|
33
|
+
# argument is a set of non-required options.
|
34
|
+
config.vm.synced_folder "./shared", "/shared"
|
35
|
+
|
36
|
+
# Provider-specific configuration so you can fine-tune various
|
37
|
+
# backing providers for Vagrant. These expose provider-specific options.
|
38
|
+
# Example for VirtualBox:
|
39
|
+
#
|
40
|
+
# config.vm.provider :virtualbox do |vb|
|
41
|
+
# # Don't boot with headless mode
|
42
|
+
# vb.gui = true
|
43
|
+
#
|
44
|
+
# # Use VBoxManage to customize the VM. For example to change memory:
|
45
|
+
# vb.customize ["modifyvm", :id, "--memory", "1024"]
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# View the documentation for the provider you're using for more
|
49
|
+
# information on available options.
|
50
|
+
|
51
|
+
# Enable provisioning with Puppet stand alone. Puppet manifests
|
52
|
+
# are contained in a directory path relative to this Vagrantfile.
|
53
|
+
# You will need to create the manifests directory and a manifest in
|
54
|
+
# the file base.pp in the manifests_path directory.
|
55
|
+
#
|
56
|
+
# An example Puppet manifest to provision the message of the day:
|
57
|
+
#
|
58
|
+
# # group { "puppet":
|
59
|
+
# # ensure => "present",
|
60
|
+
# # }
|
61
|
+
# #
|
62
|
+
# # File { owner => 0, group => 0, mode => 0644 }
|
63
|
+
# #
|
64
|
+
# # file { '/etc/motd':
|
65
|
+
# # content => "Welcome to your Vagrant-built virtual machine!
|
66
|
+
# # Managed by Puppet.\n"
|
67
|
+
# # }
|
68
|
+
#
|
69
|
+
# config.vm.provision :puppet do |puppet|
|
70
|
+
# puppet.manifests_path = "manifests"
|
71
|
+
# puppet.manifest_file = "base.pp"
|
72
|
+
# end
|
73
|
+
|
74
|
+
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
75
|
+
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
76
|
+
# some recipes and/or roles.
|
77
|
+
#
|
78
|
+
# config.vm.provision :chef_solo do |chef|
|
79
|
+
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
80
|
+
# chef.roles_path = "../my-recipes/roles"
|
81
|
+
# chef.data_bags_path = "../my-recipes/data_bags"
|
82
|
+
# chef.add_recipe "mysql"
|
83
|
+
# chef.add_role "web"
|
84
|
+
#
|
85
|
+
# # You may also specify custom JSON attributes:
|
86
|
+
# chef.json = { :mysql_password => "foo" }
|
87
|
+
# end
|
88
|
+
|
89
|
+
# Enable provisioning with chef server, specifying the chef server URL,
|
90
|
+
# and the path to the validation key (relative to this Vagrantfile).
|
91
|
+
#
|
92
|
+
# The Opscode Platform uses HTTPS. Substitute your organization for
|
93
|
+
# ORGNAME in the URL and validation key.
|
94
|
+
#
|
95
|
+
# If you have your own Chef Server, use the appropriate URL, which may be
|
96
|
+
# HTTP instead of HTTPS depending on your configuration. Also change the
|
97
|
+
# validation key to validation.pem.
|
98
|
+
#
|
99
|
+
# config.vm.provision :chef_client do |chef|
|
100
|
+
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
101
|
+
# chef.validation_key_path = "ORGNAME-validator.pem"
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# If you're using the Opscode platform, your validator client is
|
105
|
+
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
106
|
+
#
|
107
|
+
# If you have your own Chef Server, the default validation client name is
|
108
|
+
# chef-validator, unless you changed the configuration.
|
109
|
+
#
|
110
|
+
# chef.validation_client_name = "ORGNAME-validator"
|
111
|
+
end
|
data/lib/lxc/configuration.rb
CHANGED
@@ -17,9 +17,11 @@ module LXC
|
|
17
17
|
# @return [LXC::Configuration]
|
18
18
|
def self.load_file(path)
|
19
19
|
fullpath = File.expand_path(path)
|
20
|
+
|
20
21
|
if !File.exists?(fullpath)
|
21
22
|
raise ArgumentError, "File '#{path}' does not exist."
|
22
23
|
end
|
24
|
+
|
23
25
|
LXC::Configuration.new(File.read(fullpath))
|
24
26
|
end
|
25
27
|
|
@@ -45,15 +47,20 @@ module LXC
|
|
45
47
|
def save_to_file(path)
|
46
48
|
fullpath = File.expand_path(path)
|
47
49
|
lines = []
|
50
|
+
|
48
51
|
@content.each_pair do |key,value|
|
49
52
|
k = "lxc.#{key.gsub('_', '.')}"
|
53
|
+
|
50
54
|
if value.kind_of?(Array)
|
51
55
|
lines << value.map { |v| "#{k} = #{v}" }
|
52
56
|
else
|
53
57
|
lines << "#{k} = #{value}"
|
54
58
|
end
|
55
59
|
end
|
56
|
-
|
60
|
+
|
61
|
+
File.open(path, 'w') do |f|
|
62
|
+
f.write(lines.flatten.join("\n"))
|
63
|
+
end
|
57
64
|
end
|
58
65
|
|
59
66
|
private
|
@@ -61,16 +68,24 @@ module LXC
|
|
61
68
|
def parse(data)
|
62
69
|
hash = {}
|
63
70
|
lines = data.split("\n").map(&:strip).select { |l| !l.empty? && l[0,1] != '#' }
|
71
|
+
|
64
72
|
lines.each do |l|
|
65
73
|
key,value = l.split('=').map(&:strip)
|
74
|
+
|
66
75
|
if !valid_option?(key)
|
67
76
|
raise ConfigurationError, "Invalid config attribute: #{key}."
|
68
77
|
end
|
78
|
+
|
69
79
|
key.gsub!(/^lxc\./, '').gsub!('.', '_')
|
80
|
+
|
70
81
|
hash[key] = [] if !hash.key?(key)
|
71
82
|
hash[key] << value
|
72
83
|
end
|
73
|
-
|
84
|
+
|
85
|
+
hash.each_pair do |k, v|
|
86
|
+
hash[k] = v.first if v.size == 1
|
87
|
+
end
|
88
|
+
|
74
89
|
hash
|
75
90
|
end
|
76
91
|
end
|
data/lib/lxc/container.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module LXC
|
2
2
|
class Container
|
3
3
|
attr_accessor :name
|
4
|
-
attr_reader :state
|
5
|
-
attr_reader :pid
|
6
4
|
|
7
5
|
# Initialize a new LXC::Container instance
|
8
6
|
# @param [String] name container name
|
@@ -14,17 +12,28 @@ module LXC
|
|
14
12
|
# Get container attributes hash
|
15
13
|
# @return [Hash]
|
16
14
|
def to_hash
|
17
|
-
status
|
18
|
-
{'name' => name, 'state' => state, 'pid' => pid}
|
15
|
+
status.to_hash.merge('name' => name)
|
19
16
|
end
|
20
17
|
|
21
18
|
# Get current status of container
|
22
19
|
# @return [Hash] hash with :state and :pid attributes
|
23
20
|
def status
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
output = run('info')
|
22
|
+
result = output.scan(/^state:\s+([\w]+)|pid:\s+(-?[\d]+)$/).flatten
|
23
|
+
|
24
|
+
LXC::Status.new(result.first, result.last)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get state of the container
|
28
|
+
# @return [String]
|
29
|
+
def state
|
30
|
+
status.state
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get PID of the container
|
34
|
+
# @return [Integer]
|
35
|
+
def pid
|
36
|
+
status.pid
|
28
37
|
end
|
29
38
|
|
30
39
|
# Check if container exists
|
@@ -36,19 +45,19 @@ module LXC
|
|
36
45
|
# Check if container is running
|
37
46
|
# @return [Boolean]
|
38
47
|
def running?
|
39
|
-
status
|
48
|
+
status.state == 'running'
|
40
49
|
end
|
41
50
|
|
42
51
|
# Check if container is frozen
|
43
52
|
# @return [Boolean]
|
44
53
|
def frozen?
|
45
|
-
status
|
54
|
+
status.state == 'frozen'
|
46
55
|
end
|
47
56
|
|
48
|
-
# Check if container is stopped
|
57
|
+
# Check if container is stopped
|
49
58
|
# @return [Boolean]
|
50
59
|
def stopped?
|
51
|
-
exists? && status
|
60
|
+
exists? && status.state == 'stopped'
|
52
61
|
end
|
53
62
|
|
54
63
|
# Start container
|
@@ -68,8 +77,8 @@ module LXC
|
|
68
77
|
# Restart container
|
69
78
|
# @return [Hash] container status hash
|
70
79
|
def restart
|
71
|
-
stop
|
72
|
-
|
80
|
+
stop ; start
|
81
|
+
status
|
73
82
|
end
|
74
83
|
|
75
84
|
# Freeze container
|
@@ -87,9 +96,9 @@ module LXC
|
|
87
96
|
end
|
88
97
|
|
89
98
|
# Wait for container to change status
|
90
|
-
# @param [String] state
|
99
|
+
# @param [String] state name
|
91
100
|
def wait(state)
|
92
|
-
if !LXC::Shell.valid_state?(state)
|
101
|
+
if !LXC::Shell.valid_state?(status.state)
|
93
102
|
raise ArgumentError, "Invalid container state: #{state}"
|
94
103
|
end
|
95
104
|
|
@@ -111,14 +120,14 @@ module LXC
|
|
111
120
|
# Get container cpu shares
|
112
121
|
# @return [Integer]
|
113
122
|
def cpu_shares
|
114
|
-
result = run('cgroup', "cpu.shares").strip
|
123
|
+
result = run('cgroup', "cpu.shares").to_s.strip
|
115
124
|
result.empty? ? nil : result.to_i
|
116
125
|
end
|
117
126
|
|
118
127
|
# Get container cpu usage in seconds
|
119
128
|
# @return [Float]
|
120
129
|
def cpu_usage
|
121
|
-
result = run('cgroup', "cpuacct.usage").strip
|
130
|
+
result = run('cgroup', "cpuacct.usage").to_s.strip
|
122
131
|
result.empty? ? nil : Float('%.4f' % (result.to_i / 1E9))
|
123
132
|
end
|
124
133
|
|
@@ -149,7 +158,8 @@ module LXC
|
|
149
158
|
end
|
150
159
|
|
151
160
|
if !!path[:template]
|
152
|
-
|
161
|
+
template_dir = path[:template_dir] || '/usr/lib/lxc/templates'
|
162
|
+
template_path = File.join(template_dir,"lxc-#{path[:template]}")
|
153
163
|
unless File.exists?(template_path)
|
154
164
|
raise ArgumentError, "Template #{path[:template]} does not exist."
|
155
165
|
end
|
@@ -163,7 +173,7 @@ module LXC
|
|
163
173
|
exists?
|
164
174
|
else
|
165
175
|
raise ArgumentError, "File #{path} does not exist." unless File.exists?(path)
|
166
|
-
LXC.run('create', '-
|
176
|
+
LXC.run('create', '-f', path)
|
167
177
|
exists?
|
168
178
|
end
|
169
179
|
end
|
@@ -173,12 +183,13 @@ module LXC
|
|
173
183
|
# @return [LXC::Container] new container instance
|
174
184
|
def clone_to(target)
|
175
185
|
raise ContainerError, "Container does not exist." unless exists?
|
176
|
-
|
186
|
+
|
187
|
+
if LXC.container(target).exists?
|
177
188
|
raise ContainerError, "New container already exists."
|
178
189
|
end
|
179
190
|
|
180
191
|
LXC.run('clone', '-o', name, '-n', target)
|
181
|
-
|
192
|
+
LXC.container(target)
|
182
193
|
end
|
183
194
|
|
184
195
|
# Create a new container from an existing container
|
@@ -186,11 +197,12 @@ module LXC
|
|
186
197
|
# @return [Boolean]
|
187
198
|
def clone_from(source)
|
188
199
|
raise ContainerError, "Container already exists." if exists?
|
189
|
-
|
200
|
+
|
201
|
+
unless LXC.container(source).exists?
|
190
202
|
raise ContainerError, "Source container does not exist."
|
191
203
|
end
|
192
204
|
|
193
|
-
|
205
|
+
run('clone', '-o', source)
|
194
206
|
exists?
|
195
207
|
end
|
196
208
|
|
@@ -202,18 +214,19 @@ module LXC
|
|
202
214
|
# it will be stopped first. Otherwise it will raise exception.
|
203
215
|
#
|
204
216
|
def destroy(force=false)
|
205
|
-
|
217
|
+
unless exists?
|
218
|
+
raise ContainerError, "Container does not exist."
|
219
|
+
end
|
206
220
|
|
207
221
|
if running?
|
208
|
-
if force
|
209
|
-
|
210
|
-
run('destroy', '-f')
|
222
|
+
if force == true
|
223
|
+
stop
|
211
224
|
else
|
212
225
|
raise ContainerError, "Container is running. Stop it first or use force=true"
|
213
|
-
end
|
214
|
-
|
215
|
-
|
216
|
-
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
run('destroy')
|
217
230
|
|
218
231
|
!exists?
|
219
232
|
end
|
@@ -228,20 +241,13 @@ module LXC
|
|
228
241
|
chunks = line.split(' ')
|
229
242
|
chunks.delete_at(0)
|
230
243
|
|
231
|
-
pid = chunks.shift
|
232
|
-
user = chunks.shift
|
233
|
-
cpu = chunks.shift
|
234
|
-
mem = chunks.shift
|
235
|
-
command = chunks.shift
|
236
|
-
args = chunks.join(' ')
|
237
|
-
|
238
244
|
{
|
239
|
-
'pid' =>
|
240
|
-
'user' =>
|
241
|
-
'cpu' =>
|
242
|
-
'memory' =>
|
243
|
-
'command' =>
|
244
|
-
'args' =>
|
245
|
+
'pid' => chunks.shift,
|
246
|
+
'user' => chunks.shift,
|
247
|
+
'cpu' => chunks.shift,
|
248
|
+
'memory' => chunks.shift,
|
249
|
+
'command' => chunks.shift,
|
250
|
+
'args' => chunks.join(' ')
|
245
251
|
}
|
246
252
|
end
|
247
253
|
end
|
data/lib/lxc/shell.rb
CHANGED
@@ -78,15 +78,18 @@ module LXC
|
|
78
78
|
# provide a block that returns string
|
79
79
|
def run(command, *args)
|
80
80
|
command_name = "lxc-#{command}"
|
81
|
+
|
81
82
|
unless BIN_FILES.include?(command_name)
|
82
83
|
raise ArgumentError, "Invalid command: #{command_name}."
|
83
84
|
end
|
84
85
|
|
85
86
|
cmd = ""
|
86
|
-
cmd
|
87
|
-
cmd
|
88
|
-
cmd
|
89
|
-
|
87
|
+
cmd << "sudo " if use_sudo == true
|
88
|
+
cmd << "#{command_name} #{args.join(' ')}".strip
|
89
|
+
cmd << " | #{yield}" if block_given?
|
90
|
+
|
91
|
+
child = POSIX::Spawn::Child.new(cmd.strip)
|
92
|
+
child.out
|
90
93
|
end
|
91
94
|
end
|
92
95
|
end
|
data/lib/lxc/status.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module LXC
|
2
|
+
class Status
|
3
|
+
attr_reader :state, :pid
|
4
|
+
|
5
|
+
def initialize(state, pid)
|
6
|
+
@state = state.to_s.downcase
|
7
|
+
@pid = Integer(pid)
|
8
|
+
end
|
9
|
+
|
10
|
+
def == (instance)
|
11
|
+
instance.pid == pid && instance.state == state
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
{'state' => state, 'pid' => pid}
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"state=#{state} pid=#{pid}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/lxc/version.rb
CHANGED
data/lib/lxc.rb
CHANGED
@@ -1,58 +1,67 @@
|
|
1
|
+
require 'posix/spawn'
|
1
2
|
require 'lxc/version'
|
2
|
-
require 'lxc/errors'
|
3
|
-
require 'lxc/shell'
|
4
|
-
require 'lxc/configuration_options'
|
5
|
-
require 'lxc/configuration'
|
6
|
-
require 'lxc/container'
|
7
3
|
|
8
4
|
module LXC
|
5
|
+
class Error < StandardError ; end
|
6
|
+
class ContainerError < Error ; end
|
7
|
+
class ConfigurationError < Error ; end
|
8
|
+
|
9
|
+
autoload :Shell, 'lxc/shell'
|
10
|
+
autoload :Configuration, 'lxc/configuration'
|
11
|
+
autoload :ConfigurationOptions, 'lxc/configuration_options'
|
12
|
+
autoload :Container, 'lxc/container'
|
13
|
+
autoload :Status, 'lxc/status'
|
14
|
+
|
9
15
|
class << self
|
10
16
|
include LXC::Shell
|
17
|
+
end
|
18
|
+
|
19
|
+
# Check if binary file is installed
|
20
|
+
# @param [String] binary filename
|
21
|
+
# @return [Boolean] true if installed
|
22
|
+
def self.binary_installed?(name)
|
23
|
+
path = File.join(LXC::Shell::BIN_PREFIX, name)
|
24
|
+
File.exists?(path)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Check if all binaries are present in the system
|
28
|
+
# @return [Boolean] true if binary files are found
|
29
|
+
def self.installed?
|
30
|
+
LXC::Shell::BIN_FILES.all?{ |f| binary_installed?(f) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get LXC configuration info
|
34
|
+
# @return [Hash] hash containing config groups
|
35
|
+
def self.config
|
36
|
+
str = LXC.run('checkconfig') { LXC::Shell::REMOVE_COLORS }
|
37
|
+
|
38
|
+
data = str.scan(/^([\w\s]+): (enabled|disabled)$/).map { |r|
|
39
|
+
[r.first.downcase.gsub(' ', '_'), r.last == 'enabled']
|
40
|
+
}
|
41
|
+
|
42
|
+
Hash[data]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get a single container instance
|
46
|
+
# @param [String] name of the container
|
47
|
+
# @return [LXC::Container] container instance
|
48
|
+
def self.container(name)
|
49
|
+
LXC::Container.new(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get a list of all available containers
|
53
|
+
# @param [String] select containers that match string
|
54
|
+
# @return [Array] array of LXC::Containers
|
55
|
+
def self.containers(filter=nil)
|
56
|
+
names = LXC.run('ls').split("\n").uniq
|
57
|
+
|
58
|
+
names.delete_if { |v| !v.include?(filter) } if filter.kind_of?(String)
|
59
|
+
names.map { |name| LXC::Container.new(name) }
|
60
|
+
end
|
11
61
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
path = File.join(LXC::Shell::BIN_PREFIX, name)
|
17
|
-
File.exists?(path)
|
18
|
-
end
|
19
|
-
|
20
|
-
# Check if all binaries are present in the system
|
21
|
-
# @return [Boolean] true if binary files are found
|
22
|
-
def installed?
|
23
|
-
!BIN_FILES.map { |f| binary_installed?(f) }.uniq.include?(false)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Get LXC configuration info
|
27
|
-
# @return [Hash] hash containing config groups
|
28
|
-
def config
|
29
|
-
str = LXC.run('checkconfig') { LXC::Shell::REMOVE_COLORS }
|
30
|
-
data = str.scan(/^([\w\s]+): (enabled|disabled)$/).map { |r|
|
31
|
-
[r.first.downcase.gsub(' ', '_'), r.last == 'enabled']
|
32
|
-
}
|
33
|
-
Hash[data]
|
34
|
-
end
|
35
|
-
|
36
|
-
# Get container information record
|
37
|
-
# @param [name] container name
|
38
|
-
# @return [LXC::Container] container instance
|
39
|
-
def container(name)
|
40
|
-
LXC::Container.new(name)
|
41
|
-
end
|
42
|
-
|
43
|
-
# Get a list of all available containers
|
44
|
-
# @param [String] select containers that match string
|
45
|
-
# @return [Array] array of LXC::Containers
|
46
|
-
def containers(filter=nil)
|
47
|
-
names = LXC.run('ls').split("\n").uniq
|
48
|
-
names.delete_if { |v| !v.include?(filter) } if filter.kind_of?(String)
|
49
|
-
names.map { |name| Container.new(name) }
|
50
|
-
end
|
51
|
-
|
52
|
-
# Get current LXC version
|
53
|
-
# @return [String] current LXC version
|
54
|
-
def version
|
55
|
-
LXC.run('version').strip.split(' ').last
|
56
|
-
end
|
62
|
+
# Get currently installeded LXC version
|
63
|
+
# @return [String] current LXC version
|
64
|
+
def self.version
|
65
|
+
LXC.run('version').strip.split(' ').last
|
57
66
|
end
|
58
|
-
end
|
67
|
+
end
|
@@ -8,10 +8,12 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.homepage = "http://github.com/sosedoff/lxc-ruby"
|
9
9
|
s.authors = ["Dan Sosedoff"]
|
10
10
|
s.email = ["dan.sosedoff@gmail.com"]
|
11
|
+
|
12
|
+
s.add_dependency 'posix-spawn', '~> 0.3.6'
|
11
13
|
|
12
14
|
s.add_development_dependency 'rake'
|
13
|
-
s.add_development_dependency 'rspec', '~> 2.
|
14
|
-
s.add_development_dependency 'simplecov', '~> 0.
|
15
|
+
s.add_development_dependency 'rspec', '~> 2.13'
|
16
|
+
s.add_development_dependency 'simplecov', '~> 0.7'
|
15
17
|
|
16
18
|
s.files = `git ls-files`.split("\n")
|
17
19
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/spec/configuration_spec.rb
CHANGED
@@ -3,13 +3,13 @@ require 'spec_helper'
|
|
3
3
|
describe LXC::Configuration do
|
4
4
|
it 'parses config data' do
|
5
5
|
conf = LXC::Configuration.new(fixture('configuration.txt'))
|
6
|
-
conf.content.
|
7
|
-
conf.attributes.
|
8
|
-
conf.attributes.
|
9
|
-
conf.utsname.
|
10
|
-
conf['utsname'].
|
11
|
-
conf[:utsname].
|
12
|
-
conf.network_ipv4.
|
6
|
+
expect(conf.content).to be_a Hash
|
7
|
+
expect(conf.attributes).to be_an Array
|
8
|
+
expect(conf.attributes).to_not be_empty
|
9
|
+
expect(conf.utsname).to_not be_nil
|
10
|
+
expect(conf['utsname']).to_not be_nil
|
11
|
+
expect(conf[:utsname]).to_not be_nil
|
12
|
+
expect(conf.network_ipv4).to_not be_nil
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'saves config data into file' do
|
@@ -17,6 +17,6 @@ describe LXC::Configuration do
|
|
17
17
|
conf.save_to_file('/tmp/lxc.txt')
|
18
18
|
c1 = LXC::Configuration.new(fixture('configuration.txt'))
|
19
19
|
c2 = LXC::Configuration.new(File.read('/tmp/lxc.txt'))
|
20
|
-
c1.content.
|
20
|
+
expect(c1.content).to eq(c2.content)
|
21
21
|
end
|
22
|
-
end
|
22
|
+
end
|
data/spec/container_spec.rb
CHANGED
@@ -3,28 +3,29 @@ require 'spec_helper'
|
|
3
3
|
describe LXC::Container do
|
4
4
|
subject { LXC::Container.new('app') }
|
5
5
|
|
6
|
-
it { should respond_to
|
7
|
-
it { should respond_to
|
8
|
-
it { should respond_to
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
it { should respond_to :name }
|
7
|
+
it { should respond_to :status }
|
8
|
+
it { should respond_to :state }
|
9
|
+
it { should respond_to :pid }
|
10
|
+
|
11
|
+
describe '#name' do
|
12
|
+
it 'should be set to "app"' do
|
13
|
+
expect(subject.name).to eq 'app'
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
17
|
describe '#exists?' do
|
17
18
|
context 'for existing container' do
|
18
19
|
it 'returns true' do
|
19
20
|
stub_lxc('ls') { "app\napp2" }
|
20
|
-
subject.
|
21
|
+
expect(subject).to exist
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
context 'for non-existing container' do
|
25
26
|
it 'returns false' do
|
26
27
|
stub_lxc('ls') { "app2\napp3" }
|
27
|
-
subject.
|
28
|
+
expect(subject).to_not exist
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -32,41 +33,60 @@ describe LXC::Container do
|
|
32
33
|
describe '#status' do
|
33
34
|
it 'returns STOPPED' do
|
34
35
|
stub_lxc('info', '-n', 'app') { fixture('lxc-info-stopped.txt') }
|
35
|
-
subject.status.
|
36
|
+
expect(subject.status).to eq LXC::Status.new('STOPPED', '-1')
|
36
37
|
end
|
37
38
|
|
38
39
|
it 'returns RUNNING' do
|
39
40
|
stub_lxc('info', '-n', 'app') { fixture('lxc-info-running.txt') }
|
40
|
-
subject.status.
|
41
|
+
expect(subject.status).to eq LXC::Status.new('RUNNING', '2125')
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
45
|
describe '#destroy' do
|
45
46
|
it 'raises error if container does not exist' do
|
46
47
|
stub_lxc('ls') { "app2" }
|
47
|
-
|
48
|
-
|
48
|
+
|
49
|
+
expect {
|
50
|
+
subject.destroy
|
51
|
+
}.to raise_error LXC::ContainerError, "Container does not exist."
|
49
52
|
end
|
50
53
|
|
51
54
|
it 'raises error if container is running' do
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
subject.stub(:exists?).and_return(true)
|
56
|
+
subject.stub(:running?).and_return(true)
|
57
|
+
|
58
|
+
expect {
|
59
|
+
subject.destroy
|
60
|
+
}.to raise_error LXC::ContainerError, "Container is running. Stop it first or use force=true"
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'with force=true' do
|
64
|
+
before do
|
65
|
+
stub_lxc('ls') { 'app' }
|
66
|
+
stub_lxc('info', '-n', 'app') { fixture 'lxc-info-running.txt' }
|
67
|
+
stub_lxc('stop', '-n', 'app') { '' }
|
68
|
+
stub_lxc('info', '-n', 'app') { fixture 'lxc-info-stopped.txt' }
|
69
|
+
stub_lxc('destroy', '-n', 'app') { '' }
|
70
|
+
stub_lxc('ls') { '' }
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'stops and destroys container' do
|
74
|
+
expect(subject.destroy(true)).to be_true
|
75
|
+
end
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
59
79
|
describe '#memory_usage' do
|
60
80
|
it 'returns the amount of used memory' do
|
61
81
|
stub_lxc('cgroup', '-n', 'app', 'memory.usage_in_bytes') { "3280896\n" }
|
62
|
-
subject.memory_usage.
|
82
|
+
expect(subject.memory_usage).to eq(3280896)
|
63
83
|
end
|
64
84
|
end
|
65
85
|
|
66
86
|
describe '#memory_limit' do
|
67
87
|
it 'returns the memory limit' do
|
68
88
|
stub_lxc('cgroup', '-n', 'app', 'memory.limit_in_bytes') { "268435456\n" }
|
69
|
-
subject.memory_limit.
|
89
|
+
expect(subject.memory_limit).to eq(268435456)
|
70
90
|
end
|
71
91
|
end
|
72
92
|
|
@@ -74,8 +94,9 @@ describe LXC::Container do
|
|
74
94
|
it 'raises error if container is not running' do
|
75
95
|
stub_lxc('info', '-n', 'app') { fixture('lxc-info-stopped.txt') }
|
76
96
|
|
77
|
-
|
78
|
-
|
97
|
+
expect {
|
98
|
+
subject.processes
|
99
|
+
}.to raise_error LXC::ContainerError, "Container is not running"
|
79
100
|
end
|
80
101
|
|
81
102
|
it 'returns list of all processes' do
|
@@ -83,16 +104,16 @@ describe LXC::Container do
|
|
83
104
|
stub_lxc('ps', '-n', 'app', '--', '-eo pid,user,%cpu,%mem,args') { fixture('lxc-ps-aux.txt') }
|
84
105
|
|
85
106
|
list = subject.processes
|
86
|
-
list.
|
107
|
+
expect(list).to be_an Array
|
87
108
|
|
88
109
|
p = list.first
|
89
|
-
p.
|
90
|
-
p.
|
91
|
-
p.
|
92
|
-
p.
|
93
|
-
p.
|
94
|
-
p.
|
95
|
-
p.
|
110
|
+
expect(p).to be_a Hash
|
111
|
+
expect(p).to have_key('pid')
|
112
|
+
expect(p).to have_key('user')
|
113
|
+
expect(p).to have_key('cpu')
|
114
|
+
expect(p).to have_key('memory')
|
115
|
+
expect(p).to have_key('command')
|
116
|
+
expect(p).to have_key('args')
|
96
117
|
end
|
97
118
|
end
|
98
119
|
|
@@ -100,7 +121,7 @@ describe LXC::Container do
|
|
100
121
|
context 'when container does not exist' do
|
101
122
|
it 'returns false' do
|
102
123
|
stub_lxc('ls') { "foo-app" }
|
103
|
-
subject.
|
124
|
+
expect(subject).to_not be_stopped
|
104
125
|
end
|
105
126
|
end
|
106
127
|
|
@@ -109,14 +130,14 @@ describe LXC::Container do
|
|
109
130
|
stub_lxc('ls') { 'app' }
|
110
131
|
stub_lxc('info', '-n', 'app') { fixture('lxc-info-stopped.txt') }
|
111
132
|
|
112
|
-
subject.
|
133
|
+
expect(subject).to be_stopped
|
113
134
|
end
|
114
135
|
|
115
136
|
it 'returns false if running' do
|
116
137
|
stub_lxc('ls') { 'app' }
|
117
138
|
stub_lxc('info', '-n', 'app') { fixture('lxc-info-running.txt') }
|
118
139
|
|
119
|
-
subject.
|
140
|
+
expect(subject).to_not be_stopped
|
120
141
|
end
|
121
142
|
end
|
122
143
|
end
|
@@ -128,7 +149,7 @@ describe LXC::Container do
|
|
128
149
|
end
|
129
150
|
|
130
151
|
it 'returns cpu shares value' do
|
131
|
-
subject.cpu_shares.
|
152
|
+
expect(subject.cpu_shares).to eq 1024
|
132
153
|
end
|
133
154
|
end
|
134
155
|
|
@@ -138,7 +159,17 @@ describe LXC::Container do
|
|
138
159
|
end
|
139
160
|
|
140
161
|
it 'returns nil' do
|
141
|
-
subject.cpu_shares.
|
162
|
+
expect(subject.cpu_shares).to be_nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when run command is nil' do
|
167
|
+
before do
|
168
|
+
subject.stub(:run).and_return(nil)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'should return nil' do
|
172
|
+
expect(subject.cpu_shares).to be_nil
|
142
173
|
end
|
143
174
|
end
|
144
175
|
end
|
@@ -150,7 +181,7 @@ describe LXC::Container do
|
|
150
181
|
end
|
151
182
|
|
152
183
|
it 'returns usage in seconds' do
|
153
|
-
subject.cpu_usage.
|
184
|
+
expect(subject.cpu_usage).to eq 4239.0819
|
154
185
|
end
|
155
186
|
end
|
156
187
|
|
@@ -160,7 +191,17 @@ describe LXC::Container do
|
|
160
191
|
end
|
161
192
|
|
162
193
|
it 'returns nil' do
|
163
|
-
subject.cpu_usage.
|
194
|
+
expect(subject.cpu_usage).to be_nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'when run command is nil' do
|
199
|
+
before do
|
200
|
+
subject.stub(:run).and_return(nil)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should return nil' do
|
204
|
+
expect(subject.cpu_usage).to be_nil
|
164
205
|
end
|
165
206
|
end
|
166
207
|
end
|
@@ -178,7 +219,7 @@ describe LXC::Container do
|
|
178
219
|
|
179
220
|
it 'executes a command with container name' do
|
180
221
|
stub_lxc("info", "-n", "app") { "info" }
|
181
|
-
subject.info.
|
222
|
+
expect(subject.info).to eq "info"
|
182
223
|
end
|
183
224
|
end
|
184
|
-
end
|
225
|
+
end
|
data/spec/lxc_spec.rb
CHANGED
@@ -18,101 +18,112 @@ describe LXC do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'returns true if all files are found' do
|
21
|
-
LXC.installed
|
21
|
+
expect(LXC.installed?).to be_true
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'returns false on missing files' do
|
25
25
|
FileUtils.rm("/tmp/lxc/lxc-version")
|
26
|
-
LXC.installed
|
26
|
+
expect(LXC.installed?).to be_false
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
describe '.version' do
|
31
|
+
it 'returns installed LXC version' do
|
32
|
+
stub_lxc('version') { fixture('lxc-version.txt') }
|
33
|
+
expect(LXC.version).to eq('0.7.5')
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
37
|
+
describe '.config' do
|
38
|
+
it 'returns config hash with attributes' do
|
39
|
+
stub_lxc('checkconfig') { fixture('lxc-checkconfig.txt') }
|
40
|
+
|
41
|
+
info = LXC.config
|
42
|
+
expect(info).to be_a(Hash)
|
43
|
+
|
44
|
+
expect(info['namespaces']).to be_true
|
45
|
+
expect(info['utsname_namespace']).to be_true
|
46
|
+
expect(info['ipc_namespace']).to be_true
|
47
|
+
expect(info['pid_namespace']).to be_true
|
48
|
+
expect(info['user_namespace']).to be_true
|
49
|
+
expect(info['network_namespace']).to be_true
|
50
|
+
expect(info['cgroup']).to be_true
|
51
|
+
expect(info['cgroup_clone_children_flag']).to be_true
|
52
|
+
expect(info['cgroup_device']).to be_true
|
53
|
+
expect(info['cgroup_sched']).to be_true
|
54
|
+
expect(info['cgroup_cpu_account']).to be_true
|
55
|
+
expect(info['cgroup_memory_controller']).to be_true
|
56
|
+
expect(info['cgroup_cpuset']).to be_true
|
57
|
+
expect(info['veth_pair_device']).to be_true
|
58
|
+
expect(info['macvlan']).to be_true
|
59
|
+
expect(info['vlan']).to be_true
|
60
|
+
expect(info['file_capabilities']).to be_true
|
61
|
+
end
|
58
62
|
end
|
59
63
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
c.name.should eq('foo')
|
64
|
-
end
|
64
|
+
describe '.container' do
|
65
|
+
it 'returns a container for name' do
|
66
|
+
c = LXC.container('foo')
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
list.should be_an Array
|
70
|
-
list.size.should eq(2)
|
71
|
-
list.first.should be_a LXC::Container
|
72
|
-
list.first.name.should eq('vm0')
|
68
|
+
expect(c).to be_a LXC::Container
|
69
|
+
expect(c.name).to eq('foo')
|
70
|
+
end
|
73
71
|
end
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
describe '.containers' do
|
74
|
+
it 'returns all available containers' do
|
75
|
+
stub_lxc('ls') { "vm0\nvm1\nvm0" }
|
76
|
+
|
77
|
+
list = LXC.containers
|
78
|
+
expect(list).to be_an Array
|
79
|
+
expect(list.size).to eq(2)
|
80
|
+
expect(list.first).to be_a LXC::Container
|
81
|
+
expect(list.first.name).to eq('vm0')
|
82
|
+
end
|
80
83
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
+
context 'with argument' do
|
85
|
+
it 'returns containers filtered by name' do
|
86
|
+
stub_lxc('ls') { "vm0\nvm1\nfoo\n"}
|
87
|
+
|
88
|
+
list = LXC.containers("vm")
|
89
|
+
expect(list.size).to eq(2)
|
90
|
+
end
|
84
91
|
end
|
92
|
+
end
|
85
93
|
|
86
|
-
|
87
|
-
|
94
|
+
describe '.sudo' do
|
95
|
+
before { LXC.use_sudo = true }
|
96
|
+
let(:result) do
|
97
|
+
klass = Struct.new(:out)
|
98
|
+
klass.new(fixture('lxc-version.txt'))
|
88
99
|
end
|
89
100
|
|
90
101
|
it 'executes command using sudo' do
|
91
|
-
LXC.use_sudo.
|
102
|
+
expect(LXC.use_sudo).to be_true
|
103
|
+
|
104
|
+
POSIX::Spawn::Child.stub(:new).
|
105
|
+
with('sudo lxc-version').
|
106
|
+
and_return(result)
|
92
107
|
|
93
|
-
|
94
|
-
bar.should_receive(:'`').with('sudo lxc-version').and_return(fixture('lxc-version.txt'))
|
95
|
-
bar.run('version').should_not be_empty
|
108
|
+
expect(LXC.run('version')).to eq 'lxc version: 0.7.5'
|
96
109
|
end
|
97
110
|
end
|
98
111
|
|
99
|
-
|
100
|
-
class Bar
|
101
|
-
include LXC::Shell
|
102
|
-
end
|
112
|
+
describe '.use_sudo' do
|
113
|
+
class Bar ; include LXC::Shell ; end
|
103
114
|
|
104
115
|
it 'should be true' do
|
105
116
|
foo = Bar.new
|
106
|
-
foo.use_sudo.
|
107
|
-
LXC.use_sudo.
|
117
|
+
expect(foo.use_sudo).to be_true
|
118
|
+
expect(LXC.use_sudo).to be_true
|
108
119
|
end
|
109
120
|
|
110
121
|
it 'should be false' do
|
111
122
|
LXC.use_sudo = false
|
112
123
|
foo = Bar.new
|
113
124
|
|
114
|
-
LXC.use_sudo.
|
115
|
-
foo.use_sudo.
|
125
|
+
expect(LXC.use_sudo).to be_false
|
126
|
+
expect(foo.use_sudo).to be_false
|
116
127
|
end
|
117
128
|
end
|
118
|
-
end
|
129
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
$:.unshift File.expand_path("../..", __FILE__)
|
2
2
|
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start do
|
5
|
+
add_filter "/.bundle/"
|
6
|
+
end
|
7
|
+
|
3
8
|
require 'lib/lxc'
|
4
9
|
|
5
10
|
def fixture_path(filename=nil)
|
@@ -13,5 +18,9 @@ end
|
|
13
18
|
|
14
19
|
def stub_lxc(command, *args)
|
15
20
|
output = yield
|
16
|
-
|
21
|
+
|
22
|
+
LXC.should_receive(:run).
|
23
|
+
exactly(1).times.
|
24
|
+
with(command, *args).
|
25
|
+
and_return(output)
|
17
26
|
end
|
data/spec/status_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LXC::Status do
|
4
|
+
describe '.new' do
|
5
|
+
let(:status) { LXC::Status.new('RUNNING', '12345') }
|
6
|
+
|
7
|
+
it 'makes state downcase' do
|
8
|
+
expect(status.state).to eq 'running'
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'converts given pid into integer' do
|
12
|
+
expect(status.pid).to be_an Integer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#to_hash' do
|
17
|
+
let(:status) { LXC::Status.new('RUNNING', '12345') }
|
18
|
+
|
19
|
+
it 'returns a hash representation' do
|
20
|
+
result = status.to_hash
|
21
|
+
expect(result).to be_a Hash
|
22
|
+
expect(result).to include 'state', 'pid'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#to_s' do
|
27
|
+
let(:status) { LXC::Status.new('RUNNING', '12345') }
|
28
|
+
|
29
|
+
it 'returns a string representation' do
|
30
|
+
expect(status.to_s).to eq 'state=running pid=12345'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
CHANGED
@@ -1,64 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lxc-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Dan Sosedoff
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-09-22 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: posix-spawn
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.6
|
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.6
|
14
27
|
- !ruby/object:Gem::Dependency
|
15
28
|
name: rake
|
16
29
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
30
|
requirements:
|
19
|
-
- -
|
31
|
+
- - '>='
|
20
32
|
- !ruby/object:Gem::Version
|
21
33
|
version: '0'
|
22
34
|
type: :development
|
23
35
|
prerelease: false
|
24
36
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
37
|
requirements:
|
27
|
-
- -
|
38
|
+
- - '>='
|
28
39
|
- !ruby/object:Gem::Version
|
29
40
|
version: '0'
|
30
41
|
- !ruby/object:Gem::Dependency
|
31
42
|
name: rspec
|
32
43
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
44
|
requirements:
|
35
45
|
- - ~>
|
36
46
|
- !ruby/object:Gem::Version
|
37
|
-
version: '2.
|
47
|
+
version: '2.13'
|
38
48
|
type: :development
|
39
49
|
prerelease: false
|
40
50
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
51
|
requirements:
|
43
52
|
- - ~>
|
44
53
|
- !ruby/object:Gem::Version
|
45
|
-
version: '2.
|
54
|
+
version: '2.13'
|
46
55
|
- !ruby/object:Gem::Dependency
|
47
56
|
name: simplecov
|
48
57
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
58
|
requirements:
|
51
59
|
- - ~>
|
52
60
|
- !ruby/object:Gem::Version
|
53
|
-
version: '0.
|
61
|
+
version: '0.7'
|
54
62
|
type: :development
|
55
63
|
prerelease: false
|
56
64
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
65
|
requirements:
|
59
66
|
- - ~>
|
60
67
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
68
|
+
version: '0.7'
|
62
69
|
description: Ruby wrapper to manage LXC (Linux Containers).
|
63
70
|
email:
|
64
71
|
- dan.sosedoff@gmail.com
|
@@ -72,14 +79,15 @@ files:
|
|
72
79
|
- Gemfile
|
73
80
|
- README.md
|
74
81
|
- Rakefile
|
82
|
+
- Vagrantfile
|
75
83
|
- lib/lxc.rb
|
76
84
|
- lib/lxc/configuration.rb
|
77
85
|
- lib/lxc/configuration_options.rb
|
78
86
|
- lib/lxc/container.rb
|
79
|
-
- lib/lxc/errors.rb
|
80
87
|
- lib/lxc/shell.rb
|
88
|
+
- lib/lxc/status.rb
|
81
89
|
- lib/lxc/version.rb
|
82
|
-
- lxc.gemspec
|
90
|
+
- lxc-ruby.gemspec
|
83
91
|
- spec/configuration_spec.rb
|
84
92
|
- spec/container_spec.rb
|
85
93
|
- spec/fixtures/configuration.txt
|
@@ -90,35 +98,29 @@ files:
|
|
90
98
|
- spec/fixtures/lxc-version.txt
|
91
99
|
- spec/lxc_spec.rb
|
92
100
|
- spec/spec_helper.rb
|
101
|
+
- spec/status_spec.rb
|
93
102
|
homepage: http://github.com/sosedoff/lxc-ruby
|
94
103
|
licenses: []
|
104
|
+
metadata: {}
|
95
105
|
post_install_message:
|
96
106
|
rdoc_options: []
|
97
107
|
require_paths:
|
98
108
|
- lib
|
99
109
|
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
-
none: false
|
101
110
|
requirements:
|
102
|
-
- -
|
111
|
+
- - '>='
|
103
112
|
- !ruby/object:Gem::Version
|
104
113
|
version: '0'
|
105
|
-
segments:
|
106
|
-
- 0
|
107
|
-
hash: 2803095474129589431
|
108
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
115
|
requirements:
|
111
|
-
- -
|
116
|
+
- - '>='
|
112
117
|
- !ruby/object:Gem::Version
|
113
118
|
version: '0'
|
114
|
-
segments:
|
115
|
-
- 0
|
116
|
-
hash: 2803095474129589431
|
117
119
|
requirements: []
|
118
120
|
rubyforge_project:
|
119
|
-
rubygems_version:
|
121
|
+
rubygems_version: 2.0.5
|
120
122
|
signing_key:
|
121
|
-
specification_version:
|
123
|
+
specification_version: 4
|
122
124
|
summary: Ruby wrapper to LXC
|
123
125
|
test_files:
|
124
126
|
- spec/configuration_spec.rb
|
@@ -131,3 +133,5 @@ test_files:
|
|
131
133
|
- spec/fixtures/lxc-version.txt
|
132
134
|
- spec/lxc_spec.rb
|
133
135
|
- spec/spec_helper.rb
|
136
|
+
- spec/status_spec.rb
|
137
|
+
has_rdoc:
|