testlab 1.0.1 → 1.1.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/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
|