lxc 0.0.1 → 0.0.2
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/.gitignore +2 -0
- data/.rspec +1 -0
- data/.rvmrc.template +1 -0
- data/.travis.yml +16 -0
- data/LICENSE +202 -22
- data/README.md +28 -16
- data/Rakefile +82 -2
- data/bin/lxc-console +19 -0
- data/lib/lxc.rb +178 -3
- data/lib/lxc/container.rb +193 -0
- data/lib/lxc/version.rb +2 -2
- data/lxc.gemspec +27 -14
- data/spec/fixtures/0.7.5/lxc-checkconfig.out +28 -0
- data/spec/fixtures/0.7.5/lxc-ls-w-containers.out +2 -0
- data/spec/fixtures/0.7.5/lxc-ls-wo-containers.out +0 -0
- data/spec/fixtures/0.7.5/lxc-ps.out +4 -0
- data/spec/fixtures/0.7.5/lxc-version.out +1 -0
- data/spec/fixtures/0.8.0-rc2/lxc-checkconfig.out +28 -0
- data/spec/fixtures/0.8.0-rc2/lxc-ls-w-containers.out +2 -0
- data/spec/fixtures/0.8.0-rc2/lxc-ls-wo-containers.out +0 -0
- data/spec/fixtures/0.8.0-rc2/lxc-ps.out +4 -0
- data/spec/fixtures/0.8.0-rc2/lxc-version.out +1 -0
- data/spec/lxc_spec.rb +193 -0
- data/spec/spec_helper.rb +51 -0
- metadata +175 -9
@@ -0,0 +1,193 @@
|
|
1
|
+
class LXC
|
2
|
+
class ContainerError < Error; end
|
3
|
+
|
4
|
+
class Container
|
5
|
+
|
6
|
+
# An array containing the valid container states extracted from the LXC
|
7
|
+
# c-source code.
|
8
|
+
STATES = %w(stopped starting running stopping aborting freezing frozen thawed)
|
9
|
+
|
10
|
+
# @!method stopped?
|
11
|
+
# Returns true if the container is stopped, false otherwise.
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @!method starting?
|
15
|
+
# Returns true if the container is starting, false otherwise.
|
16
|
+
# @return [Boolean]
|
17
|
+
#
|
18
|
+
# @!method running?
|
19
|
+
# Returns true if the container is running, false otherwise.
|
20
|
+
# @return [Boolean]
|
21
|
+
#
|
22
|
+
# @!method stopping?
|
23
|
+
# Returns true if the container is stopping, false otherwise.
|
24
|
+
# @return [Boolean]
|
25
|
+
#
|
26
|
+
# @!method aborting?
|
27
|
+
# Returns true if the container is aborting, false otherwise.
|
28
|
+
# @return [Boolean]
|
29
|
+
#
|
30
|
+
# @!method freezing?
|
31
|
+
# Returns true if the container is freezing, false otherwise.
|
32
|
+
# @return [Boolean]
|
33
|
+
#
|
34
|
+
# @!method frozen?
|
35
|
+
# Returns true if the container is frozen, false otherwise.
|
36
|
+
# @return [Boolean]
|
37
|
+
#
|
38
|
+
# @!method thawed?
|
39
|
+
# Returns true if the container is thawed, false otherwise.
|
40
|
+
# @return [Boolean]
|
41
|
+
STATES.each do |state|
|
42
|
+
define_method "#{state.downcase}?" do
|
43
|
+
(self.state == state.downcase.to_sym)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# RegEx pattern for extracting the container state from the "lxc-info"
|
48
|
+
# command output.
|
49
|
+
REGEX_STATE = /^state:\s+([\w]+)$/
|
50
|
+
|
51
|
+
# RegEx pattern for extracting the container PID from the "lxc-info"
|
52
|
+
# command output.
|
53
|
+
REGEX_PID = /^pid:\s+([\d]+)$/
|
54
|
+
|
55
|
+
# Returns the container name
|
56
|
+
#
|
57
|
+
# @return [String] Container name
|
58
|
+
attr_reader :name
|
59
|
+
|
60
|
+
def initialize(lxc, name)
|
61
|
+
raise ContainerError, "You must supply a LXC object!" if lxc.nil?
|
62
|
+
raise ContainerError, "You must supply a container name!" if (name.nil? || name.empty?)
|
63
|
+
|
64
|
+
@lxc = lxc
|
65
|
+
@name = name
|
66
|
+
end
|
67
|
+
|
68
|
+
# Start the container
|
69
|
+
#
|
70
|
+
# Runs the "lxc-start" command with the "--daemon" flag.
|
71
|
+
#
|
72
|
+
# @param [Array] args Additional command-line arguments.
|
73
|
+
# @return [Symbol] The state of the container.
|
74
|
+
def start(*args)
|
75
|
+
self.exec("start", "--daemon", *args)
|
76
|
+
self.state
|
77
|
+
end
|
78
|
+
|
79
|
+
# Stop the container
|
80
|
+
#
|
81
|
+
# Runs the "lxc-stop" command.
|
82
|
+
#
|
83
|
+
# @param [Array] args Additional command-line arguments.
|
84
|
+
# @return [Symbol] The state of the container.
|
85
|
+
def stop(*args)
|
86
|
+
self.exec("stop", *args)
|
87
|
+
self.state
|
88
|
+
end
|
89
|
+
|
90
|
+
# Restart the container
|
91
|
+
def restart(options={})
|
92
|
+
self.stop
|
93
|
+
self.start
|
94
|
+
end
|
95
|
+
alias :reload :restart
|
96
|
+
|
97
|
+
# Freeze the container
|
98
|
+
#
|
99
|
+
# Runs the "lxc-freeze" command.
|
100
|
+
#
|
101
|
+
# @param [Array] args Additional command-line arguments.
|
102
|
+
# @return [Symbol] The state of the container.
|
103
|
+
def freeze(*args)
|
104
|
+
self.exec("freeze", *args)
|
105
|
+
self.state
|
106
|
+
end
|
107
|
+
|
108
|
+
# Unfreeze (thaw) the container
|
109
|
+
#
|
110
|
+
# Runs the "lxc-unfreeze" command.
|
111
|
+
#
|
112
|
+
# @param [Array] args Additional command-line arguments.
|
113
|
+
# @return [Symbol] The state of the container.
|
114
|
+
def unfreeze(*args)
|
115
|
+
self.exec("unfreeze", *args)
|
116
|
+
self.state
|
117
|
+
end
|
118
|
+
|
119
|
+
# Information on the container
|
120
|
+
#
|
121
|
+
# Runs the "lxc-info" command.
|
122
|
+
#
|
123
|
+
# @param [Array] args Additional command-line arguments.
|
124
|
+
# @return [Array] Lines of output from the executed command.
|
125
|
+
def info(*args)
|
126
|
+
self.exec("info", *args).split("\n").uniq.flatten
|
127
|
+
end
|
128
|
+
|
129
|
+
# State of the container
|
130
|
+
#
|
131
|
+
# Runs the "lxc-info" command with the "--state" flag.
|
132
|
+
#
|
133
|
+
# @param [Array] args Additional command-line arguments.
|
134
|
+
# @return [Symbol] Current state of the container.
|
135
|
+
def state(*args)
|
136
|
+
result = self.info("--state", *args).collect{ |str| str.scan(REGEX_STATE) }
|
137
|
+
result.flatten!.compact!
|
138
|
+
|
139
|
+
result.first.strip.downcase.to_sym
|
140
|
+
end
|
141
|
+
|
142
|
+
# PID of the container
|
143
|
+
#
|
144
|
+
# Runs the "lxc-info" command with the "--pid" flag.
|
145
|
+
#
|
146
|
+
# @param [Array] args Additional command-line arguments.
|
147
|
+
# @return [Integer] Current PID of the container.
|
148
|
+
def pid(*args)
|
149
|
+
result = self.info("--pid", *args).collect{ |str| str.scan(REGEX_PID) }
|
150
|
+
result.flatten!.compact!
|
151
|
+
|
152
|
+
result.first.strip.to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
# Does the container exist?
|
156
|
+
#
|
157
|
+
# @return [Boolean] Returns true if the container exists, false otherwise.
|
158
|
+
def exists?
|
159
|
+
@lxc.exists?(self.name)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Linux container command execution wrapper
|
163
|
+
#
|
164
|
+
# Executes the supplied command by injecting the container name into the
|
165
|
+
# argument list and then passes to the arguments to the top-level LXC class
|
166
|
+
# exec method.
|
167
|
+
#
|
168
|
+
# @param [Array] args Additional command-line arguments.
|
169
|
+
# @return [Array<String>] Stripped output text of the executed command.
|
170
|
+
#
|
171
|
+
# @see LXC#exec
|
172
|
+
def exec(*args)
|
173
|
+
arguments = Array.new
|
174
|
+
arguments << args.shift
|
175
|
+
arguments << "--name=#{self.name}"
|
176
|
+
arguments << args
|
177
|
+
arguments.flatten!.compact!
|
178
|
+
|
179
|
+
@lxc.exec(*arguments)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Provides a concise string representation of the class
|
183
|
+
# @return [String]
|
184
|
+
def inspect
|
185
|
+
tags = Array.new
|
186
|
+
tags << "name=#{self.name.inspect}"
|
187
|
+
tags = tags.join(' ')
|
188
|
+
|
189
|
+
"#<LXC::Container #{tags}>"
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
data/lib/lxc/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
class LXC
|
2
|
+
VERSION = "0.0.2" unless const_defined?(:VERSION)
|
3
3
|
end
|
data/lxc.gemspec
CHANGED
@@ -1,17 +1,30 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'lxc/version'
|
3
5
|
|
4
|
-
Gem::Specification.new do |
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "lxc"
|
8
|
+
spec.version = LXC::VERSION
|
9
|
+
spec.authors = ["Zachary Patten"]
|
10
|
+
spec.email = ["zachary@jovelabs.com"]
|
11
|
+
spec.description = %q(An interface for controlling local or remote Linux Containers (LXC))
|
12
|
+
spec.summary = %q(An interface for controlling local or remote Linux Containers (LXC))
|
13
|
+
spec.homepage = "https://github.com/zpatten/lxc"
|
14
|
+
spec.license = "Apache 2.0"
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency("ztk")
|
22
|
+
|
23
|
+
spec.add_development_dependency("bundler", "~> 1.3")
|
24
|
+
spec.add_development_dependency("pry")
|
25
|
+
spec.add_development_dependency("rake")
|
26
|
+
spec.add_development_dependency("redcarpet")
|
27
|
+
spec.add_development_dependency("rspec")
|
28
|
+
spec.add_development_dependency("simplecov")
|
29
|
+
spec.add_development_dependency("yard")
|
17
30
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Kernel config /proc/config.gz not found, looking in other places...
|
2
|
+
Found kernel config file /boot/config-3.2.0-23-generic
|
3
|
+
--- Namespaces ---
|
4
|
+
Namespaces: enabled
|
5
|
+
Utsname namespace: enabled
|
6
|
+
Ipc namespace: enabled
|
7
|
+
Pid namespace: enabled
|
8
|
+
User namespace: enabled
|
9
|
+
Network namespace: enabled
|
10
|
+
Multiple /dev/pts instances: enabled
|
11
|
+
|
12
|
+
--- Control groups ---
|
13
|
+
Cgroup: enabled
|
14
|
+
Cgroup clone_children flag: enabled
|
15
|
+
Cgroup device: enabled
|
16
|
+
Cgroup sched: enabled
|
17
|
+
Cgroup cpu account: enabled
|
18
|
+
Cgroup memory controller: enabled
|
19
|
+
Cgroup cpuset: enabled
|
20
|
+
|
21
|
+
--- Misc ---
|
22
|
+
Veth pair device: enabled
|
23
|
+
Macvlan: enabled
|
24
|
+
Vlan: enabled
|
25
|
+
File capabilities: enabled
|
26
|
+
|
27
|
+
Note : Before booting a new kernel, you can check its configuration
|
28
|
+
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
lxc version: 0.7.5
|
@@ -0,0 +1,28 @@
|
|
1
|
+
Kernel config /proc/config.gz not found, looking in other places...
|
2
|
+
Found kernel config file /boot/config-2.6.32-358.2.1.el6.centos.plus.x86_64
|
3
|
+
--- Namespaces ---
|
4
|
+
Namespaces: enabled
|
5
|
+
Utsname namespace: enabled
|
6
|
+
Ipc namespace: enabled
|
7
|
+
Pid namespace: enabled
|
8
|
+
User namespace: enabled
|
9
|
+
Network namespace: enabled
|
10
|
+
Multiple /dev/pts instances: enabled
|
11
|
+
|
12
|
+
--- Control groups ---
|
13
|
+
Cgroup: enabled
|
14
|
+
Cgroup namespace: enabled
|
15
|
+
Cgroup device: enabled
|
16
|
+
Cgroup sched: enabled
|
17
|
+
Cgroup cpu account: enabled
|
18
|
+
Cgroup memory controller: enabled
|
19
|
+
Cgroup cpuset: enabled
|
20
|
+
|
21
|
+
--- Misc ---
|
22
|
+
Veth pair device: enabled
|
23
|
+
Macvlan: enabled
|
24
|
+
Vlan: enabled
|
25
|
+
File capabilities: enabled
|
26
|
+
|
27
|
+
Note : Before booting a new kernel, you can check its configuration
|
28
|
+
usage : CONFIG=/path/to/config /usr/bin/lxc-checkconfig
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
lxc version: 0.8.0-rc2
|
data/spec/lxc_spec.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe LXC do
|
4
|
+
|
5
|
+
subject { LXC.new }
|
6
|
+
|
7
|
+
describe "class" do
|
8
|
+
|
9
|
+
it "should be an instance of LXC" do
|
10
|
+
subject.should be_an_instance_of LXC
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "defaults" do
|
14
|
+
|
15
|
+
it "should have use_sudo set to false" do
|
16
|
+
subject.use_sudo.should == false
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have use_ssh set to nil" do
|
20
|
+
subject.use_ssh.should == nil
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "methods" do
|
28
|
+
|
29
|
+
LXC_VERSIONS.each do |lxc_version|
|
30
|
+
|
31
|
+
context "LXC Target Version #{lxc_version}" do
|
32
|
+
|
33
|
+
describe "ls" do
|
34
|
+
|
35
|
+
context "with containers" do
|
36
|
+
|
37
|
+
it "should return an array of strings populated with container names" do
|
38
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-w-containers.out") }
|
39
|
+
|
40
|
+
subject.ls.should be_kind_of(Array)
|
41
|
+
subject.ls.should_not be_empty
|
42
|
+
subject.ls.size.should eq(1)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
context "without containers" do
|
48
|
+
|
49
|
+
it "should return an empty array" do
|
50
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-wo-containers.out") }
|
51
|
+
|
52
|
+
subject.ls.should be_kind_of(Array)
|
53
|
+
subject.ls.should be_empty
|
54
|
+
subject.ls.size.should eq(0)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "exists?" do
|
62
|
+
|
63
|
+
context "with containers" do
|
64
|
+
|
65
|
+
it "should return false if the container does not exist" do
|
66
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-w-containers.out") }
|
67
|
+
subject.exists?("abc-123-test-container-name").should == false
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return true if the container does exist" do
|
71
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-w-containers.out") }
|
72
|
+
subject.exists?("devop-test-1").should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context "without containers" do
|
78
|
+
|
79
|
+
it "should return false if the container does not exist" do
|
80
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-wo-containers.out") }
|
81
|
+
subject.exists?("abc-123-test-container-name").should == false
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return false if the container does not exist" do
|
85
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-wo-containers.out") }
|
86
|
+
subject.exists?("devop-test-1").should == false
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "ps" do
|
94
|
+
it "should return an array of strings representing the lxc process list" do
|
95
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ps.out") }
|
96
|
+
|
97
|
+
subject.ps.should be_kind_of(Array)
|
98
|
+
subject.ps.should_not be_empty
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "version" do
|
103
|
+
it "should return a string representation of the installed LXC version" do
|
104
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, 'lxc-version.out') }
|
105
|
+
|
106
|
+
subject.version.should be_kind_of(String)
|
107
|
+
subject.version.should_not be_empty
|
108
|
+
subject.version.should == lxc_version
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "checkconfig" do
|
113
|
+
it "should return an array of strings representing the LXC configuration" do
|
114
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, 'lxc-checkconfig.out') }
|
115
|
+
|
116
|
+
subject.checkconfig.should be_kind_of(Array)
|
117
|
+
subject.checkconfig.should_not be_empty
|
118
|
+
|
119
|
+
subject.checkconfig.first.should be_kind_of(String)
|
120
|
+
subject.checkconfig.first.should_not be_empty
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "container" do
|
125
|
+
it "should return a container object for the requested container" do
|
126
|
+
result = subject.container("devop-test-1")
|
127
|
+
result.should be_an_instance_of(::LXC::Container)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "containers" do
|
132
|
+
|
133
|
+
context "with containers" do
|
134
|
+
it "should return an array of container objects" do
|
135
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-w-containers.out") }
|
136
|
+
|
137
|
+
subject.containers.should be_kind_of(Array)
|
138
|
+
subject.containers.size.should eq(1)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "without containers" do
|
143
|
+
it "should return an empty array" do
|
144
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-ls-wo-containers.out") }
|
145
|
+
|
146
|
+
subject.containers.should be_kind_of(Array)
|
147
|
+
subject.containers.size.should eq(0)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "inspect" do
|
154
|
+
it "should return an information string about our class instance" do
|
155
|
+
subject.inspect.should be_kind_of(String)
|
156
|
+
subject.inspect.length.should be > 0
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "exec" do
|
161
|
+
|
162
|
+
context "against local host" do
|
163
|
+
it "should exec the supplied LXC command" do
|
164
|
+
subject.stub(:exec) { lxc_fixture(lxc_version, "lxc-version.out") }
|
165
|
+
|
166
|
+
subject.exec("version").should be_kind_of(String)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "against remote host" do
|
171
|
+
before(:each) do
|
172
|
+
@ssh_connection = ::ZTK::SSH.new(
|
173
|
+
:host_name => "127.0.0.1",
|
174
|
+
:user => ENV['USER'],
|
175
|
+
:keys => "#{ENV['HOME']}/.ssh/id_rsa"
|
176
|
+
).ssh
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should exec the supplied LXC command" do
|
180
|
+
subject.use_ssh = @ssh_connection
|
181
|
+
subject.exec("version").should be_kind_of(String)
|
182
|
+
end
|
183
|
+
end if !ENV['CI'] && !ENV['TRAVIS']
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
end # LXC Version Context
|
188
|
+
|
189
|
+
end # LXC_VERSIONS
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|