testlab 0.9.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +26 -20
- data/bin/tl +2 -3
- data/features/support/Labfile.local +11 -1
- data/features/support/Labfile.vagrant +7 -1
- data/lib/commands/container.rb +3 -3
- data/lib/commands/network.rb +2 -2
- data/lib/commands/testlab.rb +15 -15
- data/lib/testlab/container/actions.rb +9 -1
- data/lib/testlab/container/io.rb +20 -7
- data/lib/testlab/container/lifecycle.rb +20 -37
- data/lib/testlab/container/lxc.rb +2 -2
- data/lib/testlab/container/status.rb +2 -2
- data/lib/testlab/container.rb +4 -2
- data/lib/testlab/labfile.rb +1 -1
- data/lib/testlab/network/actions.rb +40 -4
- data/lib/testlab/network/lifecycle.rb +14 -31
- data/lib/testlab/network/status.rb +22 -2
- data/lib/testlab/node/actions.rb +8 -0
- data/lib/testlab/node/lifecycle.rb +14 -35
- data/lib/testlab/providers/local.rb +2 -2
- data/lib/testlab/providers/vagrant.rb +0 -2
- data/lib/testlab/provisioners/apt.rb +2 -2
- data/lib/testlab/provisioners/apt_cacher_ng.rb +12 -4
- data/lib/testlab/provisioners/bind.rb +23 -11
- data/lib/testlab/provisioners/chef/omni_bus.rb +4 -4
- data/lib/testlab/provisioners/chef/omni_truck.rb +2 -2
- data/lib/testlab/provisioners/chef/ruby_gem_client.rb +4 -4
- data/lib/testlab/provisioners/chef/ruby_gem_server.rb +2 -2
- data/lib/testlab/provisioners/raring.rb +2 -2
- data/lib/testlab/provisioners/resolv.rb +7 -5
- data/lib/testlab/provisioners/route.rb +4 -4
- data/lib/testlab/provisioners/shell.rb +2 -2
- data/lib/testlab/provisioners/templates/apt/bootstrap.erb +2 -2
- data/lib/testlab/provisioners/templates/apt_cacher_ng/bootstrap.erb +0 -2
- data/lib/testlab/provisioners/templates/apt_cacher_ng/security.conf.erb +1 -0
- data/lib/testlab/provisioners/templates/bind/bind-db.erb +1 -1
- data/lib/testlab/provisioners/templates/chef/omni_bus.erb +1 -1
- data/lib/testlab/provisioners/templates/chef/omni_truck.erb +1 -1
- data/lib/testlab/provisioners/templates/chef/ruby_gem_client.erb +1 -1
- data/lib/testlab/provisioners/templates/chef/ruby_gem_server.erb +1 -1
- data/lib/testlab/provisioners/templates/raring/bootstrap.erb +2 -2
- data/lib/testlab/user/lifecycle.rb +2 -2
- data/lib/testlab/utility/gli.rb +10 -10
- data/lib/testlab/utility/misc.rb +11 -0
- data/lib/testlab/version.rb +1 -1
- data/lib/testlab.rb +12 -12
- data/spec/container_spec.rb +14 -14
- data/spec/network_spec.rb +10 -8
- data/spec/node_spec.rb +10 -10
- data/spec/provisioners/shell_spec.rb +3 -3
- data/spec/testlab_spec.rb +12 -12
- metadata +5 -4
data/README.md
CHANGED
@@ -4,11 +4,17 @@
|
|
4
4
|
[![Coverage Status](https://coveralls.io/repos/zpatten/testlab/badge.png?branch=master)](https://coveralls.io/r/zpatten/testlab)
|
5
5
|
[![Code Climate](https://codeclimate.com/github/zpatten/testlab.png)](https://codeclimate.com/github/zpatten/testlab)
|
6
6
|
|
7
|
+
# A Quick Note on Versioning
|
8
|
+
|
9
|
+
I attempt to keep TestLab in line with Semantic Versioning when incrementing version numbers. I am human so I may screw this up on, hopefully rare, occasion. Semantic Versioning is delicious and everyone should be following this schema, especially when it comes to Ruby Gems which have a habit of pushing your projects into "dependency hell".
|
10
|
+
|
11
|
+
* http://semver.org/
|
12
|
+
|
7
13
|
# TestLab
|
8
14
|
|
9
15
|
A toolkit for building virtual computer labs.
|
10
16
|
|
11
|
-
What is TestLab? TestLab lets you iterate virtual infrastructure quickly. Using a `Labfile` you can define how you want your virtual infrastructure laid out. You can define multiple network segments and containers (i.e. boxen). TestLab will then
|
17
|
+
What is TestLab? TestLab lets you iterate virtual infrastructure quickly. Using a `Labfile` you can define how you want your virtual infrastructure laid out. You can define multiple network segments and containers (i.e. boxen). TestLab will then build and demolish this virtual infrastructure as you have dictated in the `Labfile`.
|
12
18
|
|
13
19
|
TestLab can also import and export containers, making it easy to share them. TestLab supports the latest LXC versions, allowing for ephemeral cloning operations, furthering your ability to iterate quickly. TestLab can be used for many other applications, including infrastructure unit and integration testing, allowing for vastly more complex configurations and more effective resource sharing than traditional VM solutions.
|
14
20
|
|
@@ -26,11 +32,11 @@ The TestLab command-line program `tl` follows in the style of git:
|
|
26
32
|
tl [global options] command [command options] [arguments...]
|
27
33
|
|
28
34
|
VERSION
|
29
|
-
0.
|
35
|
+
0.9.1
|
30
36
|
|
31
37
|
GLOBAL OPTIONS
|
32
38
|
-l, --labfile=path/to/file - Path to Labfile: ${REPO}/Labfile (default: none)
|
33
|
-
-r, --repo=path/to/directory - Path to Repository directory: ${PWD} (default: /home/zpatten/code/
|
39
|
+
-r, --repo=path/to/directory - Path to Repository directory: ${PWD} (default: /home/zpatten/code/chef-repo)
|
34
40
|
-c, --config=path/to/directory - Path to Configuration directory: ${REPO}/.testlab-$(hostname -s) (default: none)
|
35
41
|
--version - Display the program version
|
36
42
|
-v, --[no-]verbose - Show verbose output
|
@@ -38,19 +44,19 @@ The TestLab command-line program `tl` follows in the style of git:
|
|
38
44
|
--help - Show this message
|
39
45
|
|
40
46
|
COMMANDS
|
41
|
-
help
|
42
|
-
container
|
43
|
-
network
|
44
|
-
node
|
45
|
-
create
|
46
|
-
destroy
|
47
|
-
up
|
48
|
-
down
|
49
|
-
|
50
|
-
|
51
|
-
build
|
52
|
-
demolish
|
53
|
-
status
|
47
|
+
help - Shows a list of commands or help for one command
|
48
|
+
container - Manage lab containers
|
49
|
+
network - Manage lab networks
|
50
|
+
node - Manage lab nodes
|
51
|
+
create - Create the lab components
|
52
|
+
destroy - Destroy the lab components
|
53
|
+
up - On-line the lab components
|
54
|
+
down - Off-line the lab components
|
55
|
+
provision - Provision the lab components
|
56
|
+
deprovision - De-provision the lab components
|
57
|
+
build - Build the lab
|
58
|
+
demolish - Demolish the lab
|
59
|
+
status - Display the lab status
|
54
60
|
|
55
61
|
You stand up your lab with the following command:
|
56
62
|
|
@@ -107,8 +113,8 @@ You can individually online, offline, create or destroy containers:
|
|
107
113
|
|
108
114
|
tl container down -n server-www-1
|
109
115
|
tl container up -n server-www-1
|
110
|
-
tl container
|
111
|
-
tl container
|
116
|
+
tl container provision -n server-www-1
|
117
|
+
tl container deprovision -n server-www-1
|
112
118
|
|
113
119
|
You can recycle a container, effectively destroying then creating it again, provisioning it back to a "pristine" condition.
|
114
120
|
|
@@ -159,9 +165,9 @@ We can even recycle it while it is in a cloned state:
|
|
159
165
|
|
160
166
|
$ tl container recycle -n server-www-1
|
161
167
|
|
162
|
-
We can run
|
168
|
+
We can run provision against a clone as well (note: running `build`, calls `up`, which would revert us back to a non-cloned container and we would not want this to happen):
|
163
169
|
|
164
|
-
$ tl container
|
170
|
+
$ tl container provision -n server-www-1
|
165
171
|
|
166
172
|
## Network Routes
|
167
173
|
|
data/bin/tl
CHANGED
@@ -109,9 +109,6 @@ post do |global,command,options,args|
|
|
109
109
|
end
|
110
110
|
|
111
111
|
on_error do |exception|
|
112
|
-
testlab_run_time = (Time.now.utc - @testlab_start_time)
|
113
|
-
|
114
|
-
@ui.stderr.puts
|
115
112
|
@ui.stderr.puts(format_message(["ERROR:".red, exception.inspect.red.bold].join(' ')))
|
116
113
|
|
117
114
|
case exception
|
@@ -124,6 +121,8 @@ on_error do |exception|
|
|
124
121
|
|
125
122
|
false
|
126
123
|
else
|
124
|
+
testlab_run_time = (Time.now.utc - @testlab_start_time)
|
125
|
+
|
127
126
|
@logger.fatal { exception.inspect }
|
128
127
|
exception.backtrace.each do |line|
|
129
128
|
@logger.logdev.write("#{line}\n")
|
@@ -5,7 +5,12 @@ node 'vagrant' do
|
|
5
5
|
|
6
6
|
provider TestLab::Provider::Local
|
7
7
|
|
8
|
-
provisioners [
|
8
|
+
provisioners [
|
9
|
+
TestLab::Provisioner::Raring,
|
10
|
+
TestLab::Provisioner::AptCacherNG,
|
11
|
+
TestLab::Provisioner::Bind,
|
12
|
+
TestLab::Provisioner::Resolv
|
13
|
+
]
|
9
14
|
|
10
15
|
config ({
|
11
16
|
:bind => {
|
@@ -14,6 +19,10 @@ node 'vagrant' do
|
|
14
19
|
})
|
15
20
|
|
16
21
|
network 'labnet' do
|
22
|
+
provisioners [
|
23
|
+
TestLab::Provisioner::Bind
|
24
|
+
]
|
25
|
+
|
17
26
|
address '10.128.0.1/16'
|
18
27
|
bridge :br_test
|
19
28
|
end
|
@@ -23,6 +32,7 @@ node 'vagrant' do
|
|
23
32
|
release "precise"
|
24
33
|
|
25
34
|
provisioners [
|
35
|
+
TestLab::Provisioner::Resolv,
|
26
36
|
TestLab::Provisioner::AptCacherNG,
|
27
37
|
TestLab::Provisioner::Apt
|
28
38
|
]
|
@@ -7,7 +7,9 @@ node 'vagrant' do
|
|
7
7
|
|
8
8
|
provisioners [
|
9
9
|
TestLab::Provisioner::Raring,
|
10
|
-
TestLab::Provisioner::
|
10
|
+
TestLab::Provisioner::AptCacherNG,
|
11
|
+
TestLab::Provisioner::Bind,
|
12
|
+
TestLab::Provisioner::Resolv
|
11
13
|
]
|
12
14
|
|
13
15
|
config ({
|
@@ -25,6 +27,10 @@ node 'vagrant' do
|
|
25
27
|
})
|
26
28
|
|
27
29
|
network 'labnet' do
|
30
|
+
provisioners [
|
31
|
+
TestLab::Provisioner::Bind
|
32
|
+
]
|
33
|
+
|
28
34
|
address '10.128.0.1/16'
|
29
35
|
bridge :br0
|
30
36
|
end
|
data/lib/commands/container.rb
CHANGED
@@ -107,18 +107,18 @@ Recycles a container. The container is taken through a series of state changes
|
|
107
107
|
|
108
108
|
The container is cycled in this order:
|
109
109
|
|
110
|
-
|
110
|
+
Deprovision -> Down -> Destroy -> Create -> Up -> Provision
|
111
111
|
EOF
|
112
112
|
c.command :recycle do |recycle|
|
113
113
|
recycle.action do |global_options, options, args|
|
114
114
|
iterate_objects_by_name(options[:name], TestLab::Container) do |container|
|
115
|
-
container.
|
115
|
+
container.deprovision
|
116
116
|
container.down
|
117
117
|
container.destroy
|
118
118
|
|
119
119
|
container.create
|
120
120
|
container.up
|
121
|
-
container.
|
121
|
+
container.provision
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
data/lib/commands/network.rb
CHANGED
@@ -54,7 +54,7 @@ EOF
|
|
54
54
|
add.action do |global_options,options,args|
|
55
55
|
iterate_objects_by_name(options[:name], TestLab::Network) do |network|
|
56
56
|
p = TestLab::Provisioner::Route.new({}, @ui)
|
57
|
-
p.
|
57
|
+
p.on_network_provision(network)
|
58
58
|
@testlab.ui.stdout.puts("Added routes successfully!".green.bold)
|
59
59
|
@testlab.ui.stdout.puts %x(netstat -nr | grep '#{network.node.ip}').strip
|
60
60
|
end
|
@@ -68,7 +68,7 @@ EOF
|
|
68
68
|
del.action do |global_options,options,args|
|
69
69
|
iterate_objects_by_name(options[:name], TestLab::Network) do |network|
|
70
70
|
p = TestLab::Provisioner::Route.new({}, @ui)
|
71
|
-
p.
|
71
|
+
p.on_network_deprovision(network)
|
72
72
|
@testlab.ui.stdout.puts("Deleted routes successfully!".red.bold)
|
73
73
|
@testlab.ui.stdout.puts %x(netstat -nr | grep '#{network.node.ip}').strip
|
74
74
|
end
|
data/lib/commands/testlab.rb
CHANGED
@@ -82,35 +82,35 @@ command :down do |down|
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
# LAB
|
86
|
-
|
85
|
+
# LAB PROVISION
|
86
|
+
################
|
87
87
|
desc 'Provision the lab components'
|
88
88
|
long_desc <<-EOF
|
89
|
-
Attempts to
|
89
|
+
Attempts to provision the defined lab components.
|
90
90
|
|
91
|
-
The components are
|
91
|
+
The components are provisioned in the following order:
|
92
92
|
|
93
93
|
Nodes -> Networks -> Containers
|
94
94
|
EOF
|
95
|
-
command :
|
96
|
-
|
97
|
-
@testlab.
|
95
|
+
command :provision do |provision|
|
96
|
+
provision.action do |global_options,options,args|
|
97
|
+
@testlab.provision
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
# LAB
|
102
|
-
|
101
|
+
# LAB DEPROVISION
|
102
|
+
##################
|
103
103
|
desc 'De-provision the lab components'
|
104
104
|
long_desc <<-EOF
|
105
|
-
Attempts to
|
105
|
+
Attempts to deprovision the defined lab components.
|
106
106
|
|
107
107
|
The components are torndown in the following order:
|
108
108
|
|
109
109
|
Containers -> Networks -> Nodes
|
110
110
|
EOF
|
111
|
-
command :
|
112
|
-
|
113
|
-
@testlab.
|
111
|
+
command :deprovision do |deprovision|
|
112
|
+
deprovision.action do |global_options,options,args|
|
113
|
+
@testlab.deprovision
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -126,7 +126,7 @@ Nodes -> Networks -> Containers
|
|
126
126
|
|
127
127
|
TestLab will then attempt to build the components, executing the following tasks for each:
|
128
128
|
|
129
|
-
Create -> Up ->
|
129
|
+
Create -> Up -> Provision
|
130
130
|
EOF
|
131
131
|
command :build do |build|
|
132
132
|
build.action do |global_options,options,args|
|
@@ -146,7 +146,7 @@ Containers -> Networks -> Nodes
|
|
146
146
|
|
147
147
|
TestLab will then attempt to demolish the components, executing the following tasks for each:
|
148
148
|
|
149
|
-
|
149
|
+
Deprovision -> Down -> Destroy
|
150
150
|
EOF
|
151
151
|
command :demolish do |demolish|
|
152
152
|
demolish.action do |global_options,options,args|
|
@@ -19,6 +19,8 @@ class TestLab
|
|
19
19
|
configure
|
20
20
|
|
21
21
|
self.lxc.create(*create_args)
|
22
|
+
|
23
|
+
do_provisioner_callbacks(self, :create, @ui)
|
22
24
|
end
|
23
25
|
|
24
26
|
true
|
@@ -38,6 +40,8 @@ class TestLab
|
|
38
40
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Destroy', :red)) do
|
39
41
|
self.lxc.destroy(%(-f))
|
40
42
|
self.lxc_clone.destroy(%(-f))
|
43
|
+
|
44
|
+
do_provisioner_callbacks(self, :destroy, @ui)
|
41
45
|
end
|
42
46
|
|
43
47
|
true
|
@@ -65,10 +69,12 @@ class TestLab
|
|
65
69
|
(self.lxc.state != :running) and raise ContainerError, "The container failed to online!"
|
66
70
|
|
67
71
|
self.users.each do |user|
|
68
|
-
user.
|
72
|
+
user.provision
|
69
73
|
end
|
70
74
|
|
71
75
|
self.ssh.exec(%(sudo hostname #{self.fqdn}))
|
76
|
+
|
77
|
+
do_provisioner_callbacks(self, :up, @ui)
|
72
78
|
end
|
73
79
|
|
74
80
|
true
|
@@ -89,6 +95,8 @@ class TestLab
|
|
89
95
|
self.lxc.stop
|
90
96
|
|
91
97
|
(self.lxc.state == :running) and raise ContainerError, "The container failed to offline!"
|
98
|
+
|
99
|
+
do_provisioner_callbacks(self, :down, @ui)
|
92
100
|
end
|
93
101
|
|
94
102
|
true
|
data/lib/testlab/container/io.rb
CHANGED
@@ -101,20 +101,33 @@ EOF
|
|
101
101
|
# Duplicates this container under another container definition.
|
102
102
|
#
|
103
103
|
# @return [Boolean] True if successful.
|
104
|
-
def copy(
|
104
|
+
def copy(target_name)
|
105
105
|
@ui.logger.debug { "Container Copy: #{self.id}" }
|
106
106
|
|
107
|
-
|
108
|
-
to_container.nil? and raise ContainerError, "We could not locate the target container!"
|
107
|
+
target_name.nil? and raise ContainerError, "You must supply a destination container!"
|
109
108
|
|
110
|
-
|
111
|
-
|
109
|
+
target_container = self.node.containers.select{ |c| c.id.to_sym == target_name.to_sym }.first
|
110
|
+
target_container.nil? and raise ContainerError, "We could not locate the target container!"
|
112
111
|
|
112
|
+
source_state = self.state
|
113
|
+
target_state = target_container.state
|
114
|
+
|
115
|
+
target_container.demolish
|
116
|
+
target_container.create
|
117
|
+
|
118
|
+
self.down
|
113
119
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Copy', :yellow)) do
|
114
|
-
self.node.ssh.exec(%(sudo rm -rf #{
|
115
|
-
self.node.ssh.exec(%(sudo rsync -a #{self.lxc.fs_root} #{
|
120
|
+
self.node.ssh.exec(%(sudo rm -rf #{target_container.lxc.fs_root}))
|
121
|
+
self.node.ssh.exec(%(sudo rsync -a #{self.lxc.fs_root} #{target_container.lxc.container_root}))
|
122
|
+
self.node.ssh.exec(%(sudo rm -fv #{File.join(self.lxc.fs_root, '.*provision')}))
|
116
123
|
end
|
117
124
|
|
125
|
+
# bring the source container back online if it was running before the copy operation
|
126
|
+
(source_state == :running) and self.up
|
127
|
+
|
128
|
+
# bring the target container back online if it was running before the copy operation
|
129
|
+
(target_state == :running) and target_container.up
|
130
|
+
|
118
131
|
true
|
119
132
|
end
|
120
133
|
|
@@ -3,53 +3,41 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Lifecycle
|
5
5
|
|
6
|
-
#
|
6
|
+
# Provision the container
|
7
7
|
#
|
8
|
-
# Attempts to
|
9
|
-
# attempt to bring it online. Afterwards the containers provisioner
|
10
|
-
# called.
|
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
11
|
#
|
12
12
|
# @return [Boolean] True if successful.
|
13
|
-
def
|
14
|
-
@ui.logger.debug { "Container
|
13
|
+
def provision
|
14
|
+
@ui.logger.debug { "Container Provision: #{self.id} " }
|
15
15
|
|
16
16
|
(self.node.state != :running) and return false
|
17
|
-
(self.
|
18
|
-
|
19
|
-
please_wait(:ui => @ui, :message => format_object_action(self, 'Setup', :green)) do
|
20
|
-
|
21
|
-
self.container_provisioners.each do |provisioner|
|
22
|
-
@ui.logger.info { ">>>>> CONTAINER PROVISIONER SETUP: #{provisioner} (#{self.id}) <<<<<" }
|
23
|
-
p = provisioner.new(self.config, @ui)
|
24
|
-
p.respond_to?(:on_container_setup) and p.on_container_setup(self)
|
25
|
-
end
|
17
|
+
(self.state != :running) and return false
|
26
18
|
|
19
|
+
please_wait(:ui => @ui, :message => format_object_action(self, :provision, :green)) do
|
20
|
+
do_provisioner_callbacks(self, :provision, @ui)
|
27
21
|
end
|
28
22
|
|
29
23
|
true
|
30
24
|
end
|
31
25
|
|
32
|
-
#
|
26
|
+
# Deprovision the container
|
33
27
|
#
|
34
|
-
# Attempts to
|
35
|
-
#
|
36
|
-
# offline the container. Afterwards the container is destroy.
|
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.
|
37
31
|
#
|
38
32
|
# @return [Boolean] True if successful.
|
39
|
-
def
|
40
|
-
@ui.logger.debug { "Container
|
33
|
+
def deprovision
|
34
|
+
@ui.logger.debug { "Container Deprovision: #{self.id} " }
|
41
35
|
|
42
36
|
(self.node.state != :running) and return false
|
43
|
-
(self.
|
44
|
-
|
45
|
-
please_wait(:ui => @ui, :message => format_object_action(self, 'Teardown', :red)) do
|
46
|
-
|
47
|
-
self.container_provisioners.each do |provisioner|
|
48
|
-
@ui.logger.info { ">>>>> CONTAINER PROVISIONER TEARDOWN: #{provisioner} (#{self.id}) <<<<<" }
|
49
|
-
p = provisioner.new(self.config, @ui)
|
50
|
-
p.respond_to?(:on_container_teardown) and p.on_container_teardown(self)
|
51
|
-
end
|
37
|
+
(self.state != :running) and return false
|
52
38
|
|
39
|
+
please_wait(:ui => @ui, :message => format_object_action(self, :deprovision, :red)) do
|
40
|
+
do_provisioner_callbacks(self, :deprovision, @ui)
|
53
41
|
end
|
54
42
|
|
55
43
|
true
|
@@ -59,25 +47,20 @@ class TestLab
|
|
59
47
|
def build
|
60
48
|
self.create
|
61
49
|
self.up
|
62
|
-
self.
|
50
|
+
self.provision
|
63
51
|
|
64
52
|
true
|
65
53
|
end
|
66
54
|
|
67
55
|
# Demolish the container
|
68
56
|
def demolish
|
69
|
-
self.
|
57
|
+
self.deprovision
|
70
58
|
self.down
|
71
59
|
self.destroy
|
72
60
|
|
73
61
|
true
|
74
62
|
end
|
75
63
|
|
76
|
-
# Returns all defined provisioners for this container's networks and the container iteself.
|
77
|
-
def container_provisioners
|
78
|
-
[self.interfaces.map(&:network).map(&:provisioners), self.provisioners].flatten.compact.uniq
|
79
|
-
end
|
80
|
-
|
81
64
|
end
|
82
65
|
|
83
66
|
end
|
@@ -17,9 +17,9 @@ class TestLab
|
|
17
17
|
# @param [String] content The content to render on the container and
|
18
18
|
# execute. This is generally a bash script of some sort for example.
|
19
19
|
# @return [String] The output of *lxc-attach*.
|
20
|
-
def bootstrap(content)
|
20
|
+
def bootstrap(content, options={})
|
21
21
|
if self.lxc_clone.exists?
|
22
|
-
self.ssh.bootstrap(content)
|
22
|
+
self.ssh.bootstrap(content, options)
|
23
23
|
else
|
24
24
|
self.lxc.bootstrap(content)
|
25
25
|
end
|
@@ -14,11 +14,11 @@ class TestLab
|
|
14
14
|
|
15
15
|
# Container CIDR
|
16
16
|
#
|
17
|
-
# Returns the CIDR of the container
|
17
|
+
# Returns the CIDR of the container.
|
18
18
|
#
|
19
19
|
# @return [Integer] The containers CIDR address.
|
20
20
|
def cidr
|
21
|
-
TestLab::Utility.cidr(self.primary_interface.address)
|
21
|
+
TestLab::Utility.cidr(self.primary_interface.address)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Container BIND PTR Record
|
data/lib/testlab/container.rb
CHANGED
@@ -14,7 +14,8 @@ class TestLab
|
|
14
14
|
# distro "ubuntu"
|
15
15
|
# release "precise"
|
16
16
|
#
|
17
|
-
# user
|
17
|
+
# user do
|
18
|
+
# username "deployer"
|
18
19
|
# password "deployer"
|
19
20
|
# uid 2600
|
20
21
|
# gid 2600
|
@@ -33,7 +34,8 @@ class TestLab
|
|
33
34
|
# distro "ubuntu"
|
34
35
|
# release "precise"
|
35
36
|
#
|
36
|
-
# user
|
37
|
+
# user do
|
38
|
+
# username "deployer"
|
37
39
|
# password "deployer"
|
38
40
|
# uid 2600
|
39
41
|
# gid 2600
|
data/lib/testlab/labfile.rb
CHANGED
@@ -7,9 +7,9 @@ class TestLab
|
|
7
7
|
#
|
8
8
|
# @author Zachary Patten <zachary AT jovelabs DOT com>
|
9
9
|
class Labfile < ZTK::DSL::Base
|
10
|
-
attribute :testlab
|
11
10
|
has_many :nodes, :class_name => 'TestLab::Node'
|
12
11
|
|
12
|
+
attribute :testlab
|
13
13
|
attribute :config, :default => Hash.new
|
14
14
|
|
15
15
|
def config_dir
|
@@ -11,7 +11,27 @@ class TestLab
|
|
11
11
|
(self.state != :not_created) and return false
|
12
12
|
|
13
13
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Create', :green)) do
|
14
|
-
self.node.ssh.
|
14
|
+
self.node.ssh.bootstrap(<<-EOF, :ignore_exit_status => true)
|
15
|
+
set -x
|
16
|
+
grep '#{def_tag}' /etc/network/interfaces && exit 0
|
17
|
+
cat <<EOI | tee -a /etc/network/interfaces
|
18
|
+
#{def_tag}
|
19
|
+
auto br0
|
20
|
+
iface #{self.bridge} inet static
|
21
|
+
bridge_ports none
|
22
|
+
bridge_stp off
|
23
|
+
bridge_fd 0
|
24
|
+
address #{self.ip}
|
25
|
+
broadcast #{self.broadcast}
|
26
|
+
netmask #{self.netmask}
|
27
|
+
#{end_tag}
|
28
|
+
EOI
|
29
|
+
brctl addbr #{self.bridge}
|
30
|
+
brctl stp #{self.bridge} off
|
31
|
+
brctl setfd #{self.bridge} 0
|
32
|
+
EOF
|
33
|
+
|
34
|
+
do_provisioner_callbacks(self, :create, @ui)
|
15
35
|
end
|
16
36
|
|
17
37
|
true
|
@@ -25,7 +45,13 @@ class TestLab
|
|
25
45
|
(self.state == :not_created) and return false
|
26
46
|
|
27
47
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Destroy', :red)) do
|
28
|
-
self.node.ssh.
|
48
|
+
self.node.ssh.bootstrap(<<-EOF, :ignore_exit_status => true)
|
49
|
+
set -x
|
50
|
+
sed -i '/#{def_tag}/,/#{end_tag}/d' /etc/network/interfaces
|
51
|
+
brctl delbr #{self.bridge}
|
52
|
+
EOF
|
53
|
+
|
54
|
+
do_provisioner_callbacks(self, :destroy, @ui)
|
29
55
|
end
|
30
56
|
|
31
57
|
true
|
@@ -39,7 +65,12 @@ class TestLab
|
|
39
65
|
(self.state == :running) and return false
|
40
66
|
|
41
67
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
|
42
|
-
self.node.ssh.
|
68
|
+
self.node.ssh.bootstrap(<<-EOF, :ignore_exit_status => true)
|
69
|
+
set -x
|
70
|
+
ifconfig #{self.bridge} #{self.ip} netmask #{self.netmask} broadcast #{self.broadcast} up
|
71
|
+
EOF
|
72
|
+
|
73
|
+
do_provisioner_callbacks(self, :up, @ui)
|
43
74
|
end
|
44
75
|
|
45
76
|
true
|
@@ -53,7 +84,12 @@ class TestLab
|
|
53
84
|
(self.state != :running) and return false
|
54
85
|
|
55
86
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
|
56
|
-
self.node.ssh.
|
87
|
+
self.node.ssh.bootstrap(<<-EOF, :ignore_exit_status => true)
|
88
|
+
set -x
|
89
|
+
ifconfig #{self.bridge} down
|
90
|
+
EOF
|
91
|
+
|
92
|
+
do_provisioner_callbacks(self, :down, @ui)
|
57
93
|
end
|
58
94
|
|
59
95
|
true
|
@@ -3,41 +3,29 @@ class TestLab
|
|
3
3
|
|
4
4
|
module Lifecycle
|
5
5
|
|
6
|
-
# Network
|
7
|
-
def
|
8
|
-
@ui.logger.debug { "Network
|
6
|
+
# Network Provision
|
7
|
+
def provision
|
8
|
+
@ui.logger.debug { "Network Provision: #{self.id} " }
|
9
9
|
|
10
10
|
(self.node.state != :running) and return false
|
11
|
-
(self.state
|
12
|
-
|
13
|
-
please_wait(:ui => @ui, :message => format_object_action(self, 'Setup', :green)) do
|
14
|
-
|
15
|
-
self.network_provisioners.each do |provisioner|
|
16
|
-
@ui.logger.info { ">>>>> NETWORK PROVISIONER SETUP: #{provisioner} (#{self.bridge}) <<<<<" }
|
17
|
-
p = provisioner.new(self.config, @ui)
|
18
|
-
p.respond_to?(:on_network_setup) and p.on_network_setup(self)
|
19
|
-
end
|
11
|
+
(self.state != :running) and return false
|
20
12
|
|
13
|
+
please_wait(:ui => @ui, :message => format_object_action(self, 'Provision', :green)) do
|
14
|
+
do_provisioner_callbacks(self, :provision, @ui)
|
21
15
|
end
|
22
16
|
|
23
17
|
true
|
24
18
|
end
|
25
19
|
|
26
|
-
# Network
|
27
|
-
def
|
28
|
-
@ui.logger.debug { "Network
|
20
|
+
# Network Deprovision
|
21
|
+
def deprovision
|
22
|
+
@ui.logger.debug { "Network Deprovision: #{self.id} " }
|
29
23
|
|
30
24
|
(self.node.state != :running) and return false
|
31
|
-
(self.state
|
32
|
-
|
33
|
-
please_wait(:ui => @ui, :message => format_object_action(self, 'Teardown', :red)) do
|
34
|
-
|
35
|
-
self.network_provisioners.each do |provisioner|
|
36
|
-
@ui.logger.info { ">>>>> NETWORK PROVISIONER TEARDOWN: #{provisioner} (#{self.bridge}) <<<<<" }
|
37
|
-
p = provisioner.new(self.config, @ui)
|
38
|
-
p.respond_to?(:on_network_teardown) and p.on_network_teardown(self)
|
39
|
-
end
|
25
|
+
(self.state != :running) and return false
|
40
26
|
|
27
|
+
please_wait(:ui => @ui, :message => format_object_action(self, 'Deprovision', :red)) do
|
28
|
+
do_provisioner_callbacks(self, :deprovision, @ui)
|
41
29
|
end
|
42
30
|
|
43
31
|
true
|
@@ -47,25 +35,20 @@ class TestLab
|
|
47
35
|
def build
|
48
36
|
self.create
|
49
37
|
self.up
|
50
|
-
self.
|
38
|
+
self.provision
|
51
39
|
|
52
40
|
true
|
53
41
|
end
|
54
42
|
|
55
43
|
# Demolish the network
|
56
44
|
def demolish
|
57
|
-
self.
|
45
|
+
self.deprovision
|
58
46
|
self.down
|
59
47
|
self.destroy
|
60
48
|
|
61
49
|
true
|
62
50
|
end
|
63
51
|
|
64
|
-
# Returns all defined provisioners for this network's containers and the network iteself.
|
65
|
-
def network_provisioners
|
66
|
-
[self.provisioners, self.interfaces.map(&:container).map(&:provisioners)].flatten.compact.uniq
|
67
|
-
end
|
68
|
-
|
69
52
|
end
|
70
53
|
|
71
54
|
end
|