testlab 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +1 -1
- data/bin/tl +5 -3
- data/features/support/Labfile.local +2 -8
- data/features/support/Labfile.vagrant +2 -5
- data/lib/testlab/container/actions.rb +1 -41
- data/lib/testlab/container/clone.rb +87 -0
- data/lib/testlab/container/configuration.rb +67 -0
- data/lib/testlab/container/io.rb +8 -8
- data/lib/testlab/container/lifecycle.rb +0 -40
- data/lib/testlab/container/lxc.rb +0 -143
- data/lib/testlab/container/provision.rb +49 -0
- data/lib/testlab/container/support.rb +47 -0
- data/lib/testlab/container.rb +10 -0
- data/lib/testlab/network/actions.rb +4 -4
- data/lib/testlab/network/lifecycle.rb +0 -28
- data/lib/testlab/network/provision.rb +37 -0
- data/lib/testlab/network/status.rb +2 -2
- data/lib/testlab/network.rb +2 -0
- data/lib/testlab/node/lifecycle.rb +0 -26
- data/lib/testlab/node/lxc.rb +1 -13
- data/lib/testlab/node/provision.rb +34 -0
- data/lib/testlab/node.rb +4 -0
- data/lib/testlab/provisioners/apt.rb +1 -0
- data/lib/testlab/provisioners/apt_cacher_ng.rb +5 -5
- data/lib/testlab/provisioners/bind.rb +35 -18
- data/lib/testlab/provisioners/chef/omni_bus.rb +3 -3
- data/lib/testlab/provisioners/chef/ruby_gem_client.rb +3 -3
- data/lib/testlab/provisioners/resolv.rb +14 -6
- data/lib/testlab/provisioners/route.rb +5 -2
- data/lib/testlab/provisioners/templates/apt/provision.erb +3 -0
- data/lib/testlab/provisioners/templates/bind/bind.erb +5 -2
- data/lib/testlab/provisioners/templates/raring/provision.erb +13 -10
- data/lib/testlab/provisioners/templates/resolv/resolv.conf.erb +4 -2
- data/lib/testlab/support/execution.rb +46 -0
- data/lib/testlab/support.rb +17 -0
- data/lib/testlab/user/lifecycle.rb +6 -6
- data/lib/testlab/utility/gli.rb +3 -3
- data/lib/testlab/utility/misc.rb +8 -0
- data/lib/testlab/version.rb +1 -1
- data/lib/testlab.rb +1 -0
- metadata +10 -8
data/README.md
CHANGED
@@ -209,7 +209,7 @@ Calling `TestLab.new` without a `:labfile` option will, by default, attempt to r
|
|
209
209
|
There are several easy accessors available to grab the first container and execute the command `uptime` on it via and SSH connection:
|
210
210
|
|
211
211
|
container = @testlab.containers.first
|
212
|
-
container.
|
212
|
+
container.exec(%(uptime))
|
213
213
|
|
214
214
|
We can also execute this command via `lxc-attach`:
|
215
215
|
|
data/bin/tl
CHANGED
@@ -101,9 +101,11 @@ end
|
|
101
101
|
post do |global,command,options,args|
|
102
102
|
testlab_run_time = (Time.now.utc - @testlab_start_time)
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
104
|
+
if !@ui.quiet?
|
105
|
+
message = format_message("TestLab v#{TestLab::VERSION} Finished (%0.4f seconds)".black.bold % testlab_run_time)
|
106
|
+
@testlab.ui.stdout.puts(message)
|
107
|
+
@testlab.ui.logger.info { message }
|
108
|
+
end
|
107
109
|
|
108
110
|
true
|
109
111
|
end
|
@@ -12,19 +12,13 @@ node 'vagrant' do
|
|
12
12
|
TestLab::Provisioner::Resolv
|
13
13
|
]
|
14
14
|
|
15
|
-
config ({
|
16
|
-
:bind => {
|
17
|
-
:domain => "default.zone"
|
18
|
-
}
|
19
|
-
})
|
20
|
-
|
21
15
|
network 'labnet' do
|
22
16
|
provisioners [
|
23
17
|
TestLab::Provisioner::Bind
|
24
18
|
]
|
25
19
|
|
26
20
|
address '10.128.0.1/16'
|
27
|
-
bridge
|
21
|
+
bridge 'br_test'
|
28
22
|
end
|
29
23
|
|
30
24
|
container "test-server" do
|
@@ -48,7 +42,7 @@ node 'vagrant' do
|
|
48
42
|
|
49
43
|
interface do
|
50
44
|
network_id 'labnet'
|
51
|
-
name
|
45
|
+
name 'eth0'
|
52
46
|
address '10.128.0.254/16'
|
53
47
|
mac '00:00:5e:63:b5:9f'
|
54
48
|
end
|
@@ -20,9 +20,6 @@ node 'vagrant' do
|
|
20
20
|
:box => 'raring64',
|
21
21
|
:box_url => 'https://dl.dropboxusercontent.com/u/22904185/boxes/raring64.box',
|
22
22
|
:file => File.dirname(__FILE__)
|
23
|
-
},
|
24
|
-
:bind => {
|
25
|
-
:domain => "default.zone"
|
26
23
|
}
|
27
24
|
})
|
28
25
|
|
@@ -32,7 +29,7 @@ node 'vagrant' do
|
|
32
29
|
]
|
33
30
|
|
34
31
|
address '10.128.0.1/16'
|
35
|
-
bridge
|
32
|
+
bridge 'br0'
|
36
33
|
end
|
37
34
|
|
38
35
|
container "test-server" do
|
@@ -56,7 +53,7 @@ node 'vagrant' do
|
|
56
53
|
|
57
54
|
interface do
|
58
55
|
network_id 'labnet'
|
59
|
-
name
|
56
|
+
name 'eth0'
|
60
57
|
address '10.128.0.254/16'
|
61
58
|
mac '00:00:5e:63:b5:9f'
|
62
59
|
end
|
@@ -72,7 +72,7 @@ class TestLab
|
|
72
72
|
user.provision
|
73
73
|
end
|
74
74
|
|
75
|
-
self.
|
75
|
+
self.exec(%(sudo hostname #{self.fqdn}))
|
76
76
|
|
77
77
|
do_provisioner_callbacks(self, :up, @ui)
|
78
78
|
end
|
@@ -102,46 +102,6 @@ class TestLab
|
|
102
102
|
true
|
103
103
|
end
|
104
104
|
|
105
|
-
# Clone the container
|
106
|
-
#
|
107
|
-
# Prepares the container, if needed, for ephemeral cloning and clones it.
|
108
|
-
#
|
109
|
-
# @return [Boolean] True if successful.
|
110
|
-
def clone
|
111
|
-
@ui.logger.debug { "Container Clone: #{self.id}" }
|
112
|
-
|
113
|
-
please_wait(:ui => @ui, :message => format_object_action(self, 'Clone', :yellow)) do
|
114
|
-
|
115
|
-
# ensure our container is in "ephemeral" mode
|
116
|
-
self.to_ephemeral
|
117
|
-
|
118
|
-
self.node.ssh.exec(%(sudo arp --verbose --delete #{self.ip}), :ignore_exit_status => true)
|
119
|
-
|
120
|
-
ephemeral_arguments = Array.new
|
121
|
-
ephemeral_arguments << %W(-o #{self.lxc_clone.name} -n #{self.lxc.name} -d)
|
122
|
-
ephemeral_arguments << %W(--keep-data) if self.persist
|
123
|
-
ephemeral_arguments.flatten!.compact!
|
124
|
-
|
125
|
-
self.lxc_clone.start_ephemeral(ephemeral_arguments)
|
126
|
-
end
|
127
|
-
|
128
|
-
true
|
129
|
-
end
|
130
|
-
|
131
|
-
# Configure the container
|
132
|
-
#
|
133
|
-
# Configures the LXC subsystem for the container.
|
134
|
-
#
|
135
|
-
# @return [Boolean] True if successful.
|
136
|
-
def configure
|
137
|
-
self.domain ||= self.node.domain
|
138
|
-
self.arch ||= detect_arch
|
139
|
-
|
140
|
-
build_lxc_config(self.lxc.config)
|
141
|
-
|
142
|
-
true
|
143
|
-
end
|
144
|
-
|
145
105
|
end
|
146
106
|
|
147
107
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
class TestLab
|
2
|
+
class Container
|
3
|
+
|
4
|
+
module Clone
|
5
|
+
|
6
|
+
# Clone the container
|
7
|
+
#
|
8
|
+
# Prepares the container, if needed, for ephemeral cloning and clones it.
|
9
|
+
#
|
10
|
+
# @return [Boolean] True if successful.
|
11
|
+
def clone
|
12
|
+
@ui.logger.debug { "Container Clone: #{self.id}" }
|
13
|
+
|
14
|
+
please_wait(:ui => @ui, :message => format_object_action(self, 'Clone', :yellow)) do
|
15
|
+
|
16
|
+
# ensure our container is in "ephemeral" mode
|
17
|
+
self.to_ephemeral
|
18
|
+
|
19
|
+
self.node.exec(%(sudo arp --verbose --delete #{self.ip}), :ignore_exit_status => true)
|
20
|
+
|
21
|
+
self.lxc_clone.start_ephemeral(clone_args)
|
22
|
+
end
|
23
|
+
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
# LXC::Container object
|
28
|
+
#
|
29
|
+
# Returns a *LXC::Container* class instance configured for the clone of
|
30
|
+
# this container.
|
31
|
+
#
|
32
|
+
# @return [LXC] An instance of LXC::Container configured for the clone of
|
33
|
+
# this container.
|
34
|
+
def lxc_clone
|
35
|
+
@lxc_clone ||= self.node.lxc.container("#{self.id}-master")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Convert to Static Container
|
39
|
+
#
|
40
|
+
# If the current container is operating as an ephemeral container, this
|
41
|
+
# will convert it back to a static container, otherwise no changes will
|
42
|
+
# occur.
|
43
|
+
#
|
44
|
+
# @return [Boolean] Returns true if successful.
|
45
|
+
def to_static
|
46
|
+
if self.lxc_clone.exists?
|
47
|
+
self.lxc.stop
|
48
|
+
self.lxc.destroy(%(-f))
|
49
|
+
|
50
|
+
self.lxc_clone.stop
|
51
|
+
self.lxc_clone.clone(%W(-o #{self.lxc_clone.name} -n #{self.lxc.name}))
|
52
|
+
self.lxc_clone.destroy(%(-f))
|
53
|
+
|
54
|
+
build_lxc_config(self.lxc.config)
|
55
|
+
end
|
56
|
+
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Convert to Ephemeral Container
|
61
|
+
#
|
62
|
+
# If the current container is operating as a static container, this will
|
63
|
+
# convert it to a ephemeral container, otherwise no changes will occur.
|
64
|
+
#
|
65
|
+
# @return [Boolean] Returns true if successful.
|
66
|
+
def to_ephemeral
|
67
|
+
if (self.lxc.exists? && !self.lxc_clone.exists?)
|
68
|
+
self.lxc_clone.stop
|
69
|
+
self.lxc_clone.destroy(%(-f))
|
70
|
+
|
71
|
+
self.lxc.stop
|
72
|
+
self.lxc.clone(%W(-o #{self.lxc.name} -n #{self.lxc_clone.name}))
|
73
|
+
self.lxc.destroy(%(-f))
|
74
|
+
|
75
|
+
build_lxc_config(self.lxc_clone.config)
|
76
|
+
else
|
77
|
+
self.lxc.stop
|
78
|
+
self.persist and self.lxc.destroy(%(-f))
|
79
|
+
end
|
80
|
+
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class TestLab
|
2
|
+
class Container
|
3
|
+
|
4
|
+
module Configuration
|
5
|
+
|
6
|
+
# Configure the container
|
7
|
+
#
|
8
|
+
# Configures the LXC subsystem for the container.
|
9
|
+
#
|
10
|
+
# @return [Boolean] True if successful.
|
11
|
+
def configure
|
12
|
+
self.domain ||= self.node.domain
|
13
|
+
self.arch ||= detect_arch
|
14
|
+
|
15
|
+
build_lxc_config(self.lxc.config)
|
16
|
+
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
# LXC Container Configuration
|
21
|
+
#
|
22
|
+
# Builds the LXC container configuration data.
|
23
|
+
#
|
24
|
+
# @return [Boolean] True if successful.
|
25
|
+
def build_lxc_config(lxc_config)
|
26
|
+
lxc_config.clear
|
27
|
+
|
28
|
+
lxc_config['lxc.arch'] = self.arch
|
29
|
+
lxc_config['lxc.utsname'] = self.fqdn
|
30
|
+
lxc_config.networks = build_lxc_network_conf(self.interfaces)
|
31
|
+
|
32
|
+
lxc_config.save
|
33
|
+
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
# LXC Network Configuration
|
38
|
+
#
|
39
|
+
# Builds an array of hashes containing the lxc configuration options for
|
40
|
+
# our network interfaces.
|
41
|
+
#
|
42
|
+
# @return [Array<Hash>] An array of hashes defining the containers
|
43
|
+
# interfaces for use in configuring LXC.
|
44
|
+
def build_lxc_network_conf(interfaces)
|
45
|
+
networks = Array.new
|
46
|
+
|
47
|
+
interfaces.each do |interface|
|
48
|
+
networks << Hash[
|
49
|
+
'lxc.network.type' => :veth,
|
50
|
+
'lxc.network.flags' => :up,
|
51
|
+
'lxc.network.link' => interface.network.bridge,
|
52
|
+
'lxc.network.name' => interface.name,
|
53
|
+
'lxc.network.hwaddr' => interface.mac,
|
54
|
+
'lxc.network.ipv4' => "#{interface.ip}/#{interface.cidr} #{interface.netmask}"
|
55
|
+
]
|
56
|
+
if (interface.primary == true) || (interfaces.count == 1)
|
57
|
+
networks.last.merge!('lxc.network.ipv4.gateway' => :auto)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
networks
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/lib/testlab/container/io.rb
CHANGED
@@ -25,7 +25,7 @@ class TestLab
|
|
25
25
|
root_fs_path = self.lxc.fs_root.split(File::SEPARATOR).last
|
26
26
|
|
27
27
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Compress', :cyan)) do
|
28
|
-
self.node.
|
28
|
+
self.node.bootstrap(<<-EOF)
|
29
29
|
set -x
|
30
30
|
set -e
|
31
31
|
|
@@ -41,7 +41,7 @@ EOF
|
|
41
41
|
|
42
42
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Export', :cyan)) do
|
43
43
|
File.exists?(local_file) and FileUtils.rm_f(local_file)
|
44
|
-
self.node.
|
44
|
+
self.node.download(remote_file, local_file)
|
45
45
|
end
|
46
46
|
|
47
47
|
@ui.stdout.puts
|
@@ -70,12 +70,12 @@ EOF
|
|
70
70
|
root_fs_path = self.lxc.fs_root.split(File::SEPARATOR).last
|
71
71
|
|
72
72
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Import', :cyan)) do
|
73
|
-
self.node.
|
74
|
-
self.node.
|
73
|
+
self.node.exec(%(sudo rm -fv #{remote_file}), :silence => true, :ignore_exit_status => true)
|
74
|
+
self.node.upload(local_file, remote_file)
|
75
75
|
end
|
76
76
|
|
77
77
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Expand', :cyan)) do
|
78
|
-
self.node.
|
78
|
+
self.node.bootstrap(<<-EOF)
|
79
79
|
set -x
|
80
80
|
set -e
|
81
81
|
|
@@ -117,9 +117,9 @@ EOF
|
|
117
117
|
|
118
118
|
self.down
|
119
119
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Copy', :yellow)) do
|
120
|
-
self.node.
|
121
|
-
self.node.
|
122
|
-
self.node.
|
120
|
+
self.node.exec(%(sudo rm -rf #{target_container.lxc.fs_root}))
|
121
|
+
self.node.exec(%(sudo rsync -a #{self.lxc.fs_root} #{target_container.lxc.container_root}))
|
122
|
+
self.node.exec(%(sudo rm -fv #{File.join(self.lxc.fs_root, '.*provision')}))
|
123
123
|
end
|
124
124
|
|
125
125
|
# bring the source container back online if it was running before the copy operation
|
@@ -3,46 +3,6 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Lifecycle
|
5
5
|
|
6
|
-
# Provision the container
|
7
|
-
#
|
8
|
-
# Attempts to provision the container. We first create the container,
|
9
|
-
# then attempt to bring it online. Afterwards the containers provisioner
|
10
|
-
# is called.
|
11
|
-
#
|
12
|
-
# @return [Boolean] True if successful.
|
13
|
-
def provision
|
14
|
-
@ui.logger.debug { "Container Provision: #{self.id} " }
|
15
|
-
|
16
|
-
(self.node.state != :running) and return false
|
17
|
-
(self.state != :running) and return false
|
18
|
-
|
19
|
-
please_wait(:ui => @ui, :message => format_object_action(self, :provision, :green)) do
|
20
|
-
do_provisioner_callbacks(self, :provision, @ui)
|
21
|
-
end
|
22
|
-
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
# Deprovision the container
|
27
|
-
#
|
28
|
-
# Attempts to deprovision the container. We first call the provisioner
|
29
|
-
# deprovision method defined for the container, if any. Next we attempt
|
30
|
-
# to offline the container. Afterwards the container is destroy.
|
31
|
-
#
|
32
|
-
# @return [Boolean] True if successful.
|
33
|
-
def deprovision
|
34
|
-
@ui.logger.debug { "Container Deprovision: #{self.id} " }
|
35
|
-
|
36
|
-
(self.node.state != :running) and return false
|
37
|
-
(self.state != :running) and return false
|
38
|
-
|
39
|
-
please_wait(:ui => @ui, :message => format_object_action(self, :deprovision, :red)) do
|
40
|
-
do_provisioner_callbacks(self, :deprovision, @ui)
|
41
|
-
end
|
42
|
-
|
43
|
-
true
|
44
|
-
end
|
45
|
-
|
46
6
|
# Build the container
|
47
7
|
def build
|
48
8
|
self.create
|
@@ -3,22 +3,6 @@ class TestLab
|
|
3
3
|
|
4
4
|
module LXC
|
5
5
|
|
6
|
-
# Container Bootstrap
|
7
|
-
#
|
8
|
-
# Renders the supplied content into a file on the container and proceeds
|
9
|
-
# to execute it on the container as root.
|
10
|
-
#
|
11
|
-
# @param [String] content The content to render on the container and
|
12
|
-
# execute. This is generally a bash script of some sort for example.
|
13
|
-
# @return [String] The output of respective SSH/LXC bootstrap.
|
14
|
-
def bootstrap(content, options={})
|
15
|
-
if self.lxc_clone.exists?
|
16
|
-
self.ssh.bootstrap(content, options)
|
17
|
-
else
|
18
|
-
self.lxc.bootstrap(content)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
6
|
# Container Console
|
23
7
|
#
|
24
8
|
# Opens an LXC console into the container.
|
@@ -41,63 +25,6 @@ class TestLab
|
|
41
25
|
@lxc ||= self.node.lxc.container(self.id)
|
42
26
|
end
|
43
27
|
|
44
|
-
# LXC::Container object
|
45
|
-
#
|
46
|
-
# Returns a *LXC::Container* class instance configured for the clone of
|
47
|
-
# this container.
|
48
|
-
#
|
49
|
-
# @return [LXC] An instance of LXC::Container configured for the clone of
|
50
|
-
# this container.
|
51
|
-
def lxc_clone
|
52
|
-
@lxc_clone ||= self.node.lxc.container("#{self.id}-master")
|
53
|
-
end
|
54
|
-
|
55
|
-
# Convert to Static Container
|
56
|
-
#
|
57
|
-
# If the current container is operating as an ephemeral container, this
|
58
|
-
# will convert it back to a static container, otherwise no changes will
|
59
|
-
# occur.
|
60
|
-
#
|
61
|
-
# @return [Boolean] Returns true if successful.
|
62
|
-
def to_static
|
63
|
-
if self.lxc_clone.exists?
|
64
|
-
self.lxc.stop
|
65
|
-
self.lxc.destroy(%(-f))
|
66
|
-
|
67
|
-
self.lxc_clone.stop
|
68
|
-
self.lxc_clone.clone(%W(-o #{self.lxc_clone.name} -n #{self.lxc.name}))
|
69
|
-
self.lxc_clone.destroy(%(-f))
|
70
|
-
|
71
|
-
build_lxc_config(self.lxc.config)
|
72
|
-
end
|
73
|
-
|
74
|
-
true
|
75
|
-
end
|
76
|
-
|
77
|
-
# Convert to Ephemeral Container
|
78
|
-
#
|
79
|
-
# If the current container is operating as a static container, this will
|
80
|
-
# convert it to a ephemeral container, otherwise no changes will occur.
|
81
|
-
#
|
82
|
-
# @return [Boolean] Returns true if successful.
|
83
|
-
def to_ephemeral
|
84
|
-
if (self.lxc.exists? && !self.lxc_clone.exists?)
|
85
|
-
self.lxc_clone.stop
|
86
|
-
self.lxc_clone.destroy(%(-f))
|
87
|
-
|
88
|
-
self.lxc.stop
|
89
|
-
self.lxc.clone(%W(-o #{self.lxc.name} -n #{self.lxc_clone.name}))
|
90
|
-
self.lxc.destroy(%(-f))
|
91
|
-
|
92
|
-
build_lxc_config(self.lxc_clone.config)
|
93
|
-
else
|
94
|
-
self.lxc.stop
|
95
|
-
self.persist and self.lxc.destroy(%(-f))
|
96
|
-
end
|
97
|
-
|
98
|
-
true
|
99
|
-
end
|
100
|
-
|
101
28
|
# Does the container exist?
|
102
29
|
#
|
103
30
|
# @return [Boolean] True if the containers exists, false otherwise.
|
@@ -114,76 +41,6 @@ class TestLab
|
|
114
41
|
self.lxc.fs_root(self.lxc_clone.exists?)
|
115
42
|
end
|
116
43
|
|
117
|
-
# Returns arguments for lxc-create based on our distro
|
118
|
-
#
|
119
|
-
# @return [Array<String>] An array of arguments for lxc-create
|
120
|
-
def create_args
|
121
|
-
case self.distro.downcase
|
122
|
-
when "ubuntu" then
|
123
|
-
%W(-f /etc/lxc/#{self.id} -t #{self.distro} -- --release #{self.release} --arch #{self.arch})
|
124
|
-
when "fedora" then
|
125
|
-
%W(-f /etc/lxc/#{self.id} -t #{self.distro} -- --release #{self.release})
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
# Attempt to detect the architecture of the node. The value returned is
|
130
|
-
# respective to the container distro.
|
131
|
-
#
|
132
|
-
# @return [String] The arch of the node in the context of the container
|
133
|
-
# distro
|
134
|
-
def detect_arch
|
135
|
-
case self.distro.downcase
|
136
|
-
when "ubuntu" then
|
137
|
-
((self.node.arch =~ /x86_64/) ? "amd64" : "i386")
|
138
|
-
when "fedora" then
|
139
|
-
((self.node.arch =~ /x86_64/) ? "amd64" : "i686")
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
# LXC Container Configuration
|
144
|
-
#
|
145
|
-
# Builds the LXC container configuration data.
|
146
|
-
#
|
147
|
-
# @return [Boolean] True if successful.
|
148
|
-
def build_lxc_config(lxc_config)
|
149
|
-
lxc_config.clear
|
150
|
-
|
151
|
-
lxc_config['lxc.arch'] = self.arch
|
152
|
-
lxc_config['lxc.utsname'] = self.fqdn
|
153
|
-
lxc_config.networks = build_lxc_network_conf(self.interfaces)
|
154
|
-
|
155
|
-
lxc_config.save
|
156
|
-
|
157
|
-
true
|
158
|
-
end
|
159
|
-
|
160
|
-
# LXC Network Configuration
|
161
|
-
#
|
162
|
-
# Builds an array of hashes containing the lxc configuration options for
|
163
|
-
# our network interfaces.
|
164
|
-
#
|
165
|
-
# @return [Array<Hash>] An array of hashes defining the containers
|
166
|
-
# interfaces for use in configuring LXC.
|
167
|
-
def build_lxc_network_conf(interfaces)
|
168
|
-
networks = Array.new
|
169
|
-
|
170
|
-
interfaces.each do |interface|
|
171
|
-
networks << Hash[
|
172
|
-
'lxc.network.type' => :veth,
|
173
|
-
'lxc.network.flags' => :up,
|
174
|
-
'lxc.network.link' => interface.network.bridge,
|
175
|
-
'lxc.network.name' => interface.name,
|
176
|
-
'lxc.network.hwaddr' => interface.mac,
|
177
|
-
'lxc.network.ipv4' => "#{interface.ip}/#{interface.cidr} #{interface.netmask}"
|
178
|
-
]
|
179
|
-
if (interface.primary == true) || (interfaces.count == 1)
|
180
|
-
networks.last.merge!('lxc.network.ipv4.gateway' => :auto)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
networks
|
185
|
-
end
|
186
|
-
|
187
44
|
end
|
188
45
|
|
189
46
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class TestLab
|
2
|
+
class Container
|
3
|
+
|
4
|
+
module Provision
|
5
|
+
|
6
|
+
# Provision the container
|
7
|
+
#
|
8
|
+
# Attempts to provision the container. We first create the container,
|
9
|
+
# then attempt to bring it online. Afterwards the containers provisioner
|
10
|
+
# is called.
|
11
|
+
#
|
12
|
+
# @return [Boolean] True if successful.
|
13
|
+
def provision
|
14
|
+
@ui.logger.debug { "Container Provision: #{self.id} " }
|
15
|
+
|
16
|
+
(self.node.state != :running) and return false
|
17
|
+
(self.state != :running) and return false
|
18
|
+
|
19
|
+
please_wait(:ui => @ui, :message => format_object_action(self, :provision, :green)) do
|
20
|
+
do_provisioner_callbacks(self, :provision, @ui)
|
21
|
+
end
|
22
|
+
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Deprovision the container
|
27
|
+
#
|
28
|
+
# Attempts to deprovision the container. We first call the provisioner
|
29
|
+
# deprovision method defined for the container, if any. Next we attempt
|
30
|
+
# to offline the container. Afterwards the container is destroy.
|
31
|
+
#
|
32
|
+
# @return [Boolean] True if successful.
|
33
|
+
def deprovision
|
34
|
+
@ui.logger.debug { "Container Deprovision: #{self.id} " }
|
35
|
+
|
36
|
+
(self.node.state != :running) and return false
|
37
|
+
(self.state != :running) and return false
|
38
|
+
|
39
|
+
please_wait(:ui => @ui, :message => format_object_action(self, :deprovision, :red)) do
|
40
|
+
do_provisioner_callbacks(self, :deprovision, @ui)
|
41
|
+
end
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class TestLab
|
2
|
+
class Container
|
3
|
+
|
4
|
+
module Support
|
5
|
+
|
6
|
+
# Returns arguments for lxc-create based on our distro
|
7
|
+
#
|
8
|
+
# @return [Array<String>] An array of arguments for lxc-create
|
9
|
+
def create_args
|
10
|
+
case self.distro.downcase
|
11
|
+
when "ubuntu" then
|
12
|
+
%W(-f /etc/lxc/#{self.id} -t #{self.distro} -- --release #{self.release} --arch #{self.arch})
|
13
|
+
when "fedora" then
|
14
|
+
%W(-f /etc/lxc/#{self.id} -t #{self.distro} -- --release #{self.release})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns arguments for lxc-start-ephemeral
|
19
|
+
#
|
20
|
+
# @return [Array<String>] An array of arguments for lxc-start-ephemeral
|
21
|
+
def clone_args
|
22
|
+
arguments = Array.new
|
23
|
+
|
24
|
+
arguments << %W(-o #{self.lxc_clone.name} -n #{self.lxc.name} -d)
|
25
|
+
arguments << %W(--keep-data) if self.persist
|
26
|
+
|
27
|
+
arguments.flatten.compact
|
28
|
+
end
|
29
|
+
|
30
|
+
# Attempt to detect the architecture of the node. The value returned is
|
31
|
+
# respective to the container distro.
|
32
|
+
#
|
33
|
+
# @return [String] The arch of the node in the context of the container
|
34
|
+
# distro
|
35
|
+
def detect_arch
|
36
|
+
case self.distro.downcase
|
37
|
+
when "ubuntu" then
|
38
|
+
((self.node.arch =~ /x86_64/) ? "amd64" : "i386")
|
39
|
+
when "fedora" then
|
40
|
+
((self.node.arch =~ /x86_64/) ? "amd64" : "i686")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/testlab/container.rb
CHANGED
@@ -77,29 +77,39 @@ class TestLab
|
|
77
77
|
# Sub-Modules
|
78
78
|
autoload :Actions, 'testlab/container/actions'
|
79
79
|
autoload :ClassMethods, 'testlab/container/class_methods'
|
80
|
+
autoload :Clone, 'testlab/container/clone'
|
81
|
+
autoload :Configuration, 'testlab/container/configuration'
|
80
82
|
autoload :Generators, 'testlab/container/generators'
|
81
83
|
autoload :Interface, 'testlab/container/interface'
|
82
84
|
autoload :IO, 'testlab/container/io'
|
83
85
|
autoload :Lifecycle, 'testlab/container/lifecycle'
|
84
86
|
autoload :LXC, 'testlab/container/lxc'
|
85
87
|
autoload :MethodMissing, 'testlab/container/method_missing'
|
88
|
+
autoload :Provision, 'testlab/container/provision'
|
86
89
|
autoload :SSH, 'testlab/container/ssh'
|
87
90
|
autoload :Status, 'testlab/container/status'
|
91
|
+
autoload :Support, 'testlab/container/support'
|
88
92
|
autoload :User, 'testlab/container/user'
|
89
93
|
|
90
94
|
include TestLab::Container::Actions
|
95
|
+
include TestLab::Container::Clone
|
96
|
+
include TestLab::Container::Configuration
|
91
97
|
include TestLab::Container::Generators
|
92
98
|
include TestLab::Container::Interface
|
93
99
|
include TestLab::Container::IO
|
94
100
|
include TestLab::Container::Lifecycle
|
95
101
|
include TestLab::Container::LXC
|
96
102
|
include TestLab::Container::MethodMissing
|
103
|
+
include TestLab::Container::Provision
|
97
104
|
include TestLab::Container::SSH
|
98
105
|
include TestLab::Container::Status
|
106
|
+
include TestLab::Container::Support
|
99
107
|
include TestLab::Container::User
|
100
108
|
|
101
109
|
extend TestLab::Container::ClassMethods
|
102
110
|
|
111
|
+
include TestLab::Support::Execution
|
112
|
+
|
103
113
|
include TestLab::Utility::Misc
|
104
114
|
|
105
115
|
# Associations and Attributes
|