testlab 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -22,17 +22,37 @@ TestLab can be run via the command-line or can be interfaced with directly via R
22
22
 
23
23
  # Using TestLab Interactively
24
24
 
25
- The TestLab command-line program `tl` follows in the style of git:
26
-
27
- $ tl help
25
+ $ tl
28
26
  NAME
29
27
  tl - TestLab - A toolkit for building virtual computer labs
30
28
 
29
+ TestLab is based around the abstraction of three main components: nodes, networks and containers. Nodes represent a system
30
+ (bare-metal or virtualized) that hosts containers. Networks repesent a Linux bridge on a node. Containers simply represent a
31
+ Linux Container (LXC) running on its parent node which is typically connected to a network on the node.
32
+
33
+ In addition to the core component abstractions, TestLab shares a series of core tasks that are universal across all of the
34
+ components. These are create and destroy, up and down, provision and deprovision. Several other core tasks, such as build,
35
+ demolish, recycle and bounce encapsulate the previously mentioned tasks and simply act as convenience tasks.
36
+
37
+ You can execute almost all of the tasks against the entire lab, or individual lab components.
38
+
39
+ When building a lab from scratch, you will typically run 'tl build'. To breakdown your lab, destroying all the components, you
40
+ will typically run 'tl demolish'. If you want to re-build the lab you can run 'tl recycle' which will run the demolish task
41
+ followed by the build task against all the lab components. If you want to power-cycle the entire lab you can run 'tl bounce'
42
+ which will run the down task followed by the up task against all the lab components. Again these tasks can be run against the
43
+ lab as a whole or individual components.
44
+
45
+ You can view the status of the entire lab using 'tl status', or view the status of individual components using 'tl node status',
46
+ 'tl network status' or 'tl container status'.
47
+
48
+ You can easily get help for any of the component tasks using the syntax 'tl help <component>'. This can be extended to the
49
+ following syntax 'tl help <task>' or 'tl help <component> <task>' for more in-depth help.
50
+
31
51
  SYNOPSIS
32
52
  tl [global options] command [command options] [arguments...]
33
53
 
34
54
  VERSION
35
- 0.9.1
55
+ 1.1.0
36
56
 
37
57
  GLOBAL OPTIONS
38
58
  -l, --labfile=path/to/file - Path to Labfile: ${REPO}/Labfile (default: none)
@@ -48,28 +68,18 @@ The TestLab command-line program `tl` follows in the style of git:
48
68
  container - Manage lab containers
49
69
  network - Manage lab networks
50
70
  node - Manage lab nodes
71
+ build - Build the lab (create->up->provision)
72
+ demolish - Demolish the lab (deprovision->down->destroy)
73
+ bounce - Bounce the lab (down->up)
74
+ recycle - Recycle the lab (demolish->build)
51
75
  create - Create the lab components
52
76
  destroy - Destroy the lab components
53
77
  up - On-line the lab components
54
78
  down - Off-line the lab components
55
79
  provision - Provision the lab components
56
80
  deprovision - De-provision the lab components
57
- build - Build the lab
58
- demolish - Demolish the lab
59
81
  status - Display the lab status
60
82
 
61
- You stand up your lab with the following command:
62
-
63
- tl build
64
-
65
- You can down the entire lab (this would only down the containers and networks on the Local provider for example):
66
-
67
- tl down
68
-
69
- You can also demolish it (only works for VM backed providers; this would be a NO-OP on the Local provider for example):
70
-
71
- tl demolish
72
-
73
83
  ## Getting Help
74
84
 
75
85
  TestLab uses the GLI RubyGem, which gives us a command line pattern similar to that of Git. Therefore help is easy to get:
@@ -79,6 +89,59 @@ TestLab uses the GLI RubyGem, which gives us a command line pattern similar to t
79
89
  tl help container
80
90
  tl help network
81
91
 
92
+ ## Container Help
93
+
94
+ Here is a sample of the help output for the container tasks:
95
+
96
+ $ tl help container
97
+ NAME
98
+ container - Manage lab containers
99
+
100
+ SYNOPSIS
101
+ tl [global options] container [command options] bounce
102
+ tl [global options] container [command options] build
103
+ tl [global options] container [command options] console
104
+ tl [global options] container [command options] [-t container|--to container] copy
105
+ tl [global options] container [command options] create
106
+ tl [global options] container [command options] demolish
107
+ tl [global options] container [command options] deprovision
108
+ tl [global options] container [command options] destroy
109
+ tl [global options] container [command options] down
110
+ tl [global options] container [command options] ephemeral
111
+ tl [global options] container [command options] [--output filename] [-c level|--compression level] export
112
+ tl [global options] container [command options] [--input filename] import
113
+ tl [global options] container [command options] persistent
114
+ tl [global options] container [command options] provision
115
+ tl [global options] container [command options] recycle
116
+ tl [global options] container [command options] [-i filename|--identity filename] [-u username|--user username] ssh
117
+ tl [global options] container [command options] ssh-config
118
+ tl [global options] container [command options] status
119
+ tl [global options] container [command options] up
120
+
121
+ COMMAND OPTIONS
122
+ -n, --name=container[,container,...] - Optional container ID or comma separated list of container IDs (default: none)
123
+
124
+ COMMANDS
125
+ build - Build containers (create->up->provision)
126
+ demolish - Demolish containers (deprovision->down->destroy)
127
+ recycle - Recycle containers (demolish->build)
128
+ bounce - Bounce containers (down->up)
129
+ create - Initialize containers
130
+ destroy - Terminate containers
131
+ up - On-line containers
132
+ down - Off-line containers
133
+ provision - Provision containers
134
+ deprovision - De-provision containers
135
+ status - Display containers status
136
+ ssh - Container SSH console
137
+ ssh-config - Container SSH configuration
138
+ console - Container console
139
+ ephemeral - Enable ephemeral mode for containers
140
+ persistent - Enable persistent mode for containers
141
+ copy - Copy containers
142
+ export - Export containers
143
+ import - Import containers
144
+
82
145
  ## Interacting with Containers
83
146
 
84
147
  Almost all commands dealing will containers will take this argument:
@@ -109,75 +172,61 @@ You can pass an optional username and/or identity to use. By default TestLab wi
109
172
  -u, --user=username - Specify an SSH Username to use (default: none)
110
173
  -i, --identity=key - Specify an SSH Identity Key to use (default: none)
111
174
 
112
- You can individually online, offline, create or destroy containers:
175
+ You can individually create or destroy, online or offline and provision or deprovision containers:
176
+
177
+ tl container create -n server-www-1
178
+ tl container destroy -n server-www-1
113
179
 
114
- tl container down -n server-www-1
115
180
  tl container up -n server-www-1
181
+ tl container down -n server-www-1
182
+
116
183
  tl container provision -n server-www-1
117
184
  tl container deprovision -n server-www-1
118
185
 
119
- You can recycle a container, effectively destroying then creating it again, provisioning it back to a "pristine" condition.
186
+ You can recycle a container, destroying then creating it again, provisioning it back to a "pristine" condition based on the `Labfile`:
120
187
 
121
188
  tl container recycle -n server-www-1
122
189
 
123
- ## Ephemeral Container Cloning
190
+ You can bounce a container, offlining then onlining it again:
124
191
 
125
- As it stands attempting to iterate infrastructure with Vagrant is a slow and painful process. Enter LXC and ephemeral cloning. The idea here is that you have a container that is provisioned to a "pristine" state according to the `Labfile`. You then clone this container and run actions against the container. After running your actions against the container you want to maybe tweak your Chef cookbook, for example, and re-run it against the container. Running an ever changing cookbook in development against the same system over and over again causes drift and problems. With the cloning you can instantly reinstate the container as it was when you first cloned it.
192
+ tl container bounce -n server-www-1
126
193
 
127
- Here we are cloning the container for the first time. It takes a bit longer than normal because TestLab is actually shutting down the container so it can be retained as the "pristine" copy of it, and starting up a ephemeral container in its place. Subsequent calls to clone are very fast.
194
+ ## Ephemeral Container Cloning
128
195
 
129
- $ tl container clone -n server-www-1
130
- [TL] TestLab v0.6.1 Loaded
131
- [TL] container server-www-1 clone # Completed in 13.0116 seconds!
132
- $ tl container clone -n server-www-1
133
- [TL] TestLab v0.6.1 Loaded
134
- [TL] container server-www-1 clone # Completed in 0.9169 seconds!
135
- $ tl container clone -n server-www-1
136
- [TL] TestLab v0.6.1 Loaded
137
- [TL] container server-www-1 clone # Completed in 1.0794 seconds!
138
- $ tl container clone -n server-www-1
139
- [TL] TestLab v0.6.1 Loaded
140
- [TL] container server-www-1 clone # Completed in 1.0281 seconds!
196
+ As it stands attempting to iterate infrastructure with Vagrant is a slow and painful process. Enter LXC and ephemeral cloning. The idea here is that you have a container that is provisioned to a "pristine" state according to the `Labfile`. You then clone this container and run actions against the container. After running your actions against the container you want to maybe tweak your Chef cookbook, for example, and re-run it against the container. Running an ever changing cookbook in development against the same system over and over again causes drift and problems. With the cloning you can instantly reinstate the container as it was when you first cloned it.
141
197
 
142
- The idea in the above example is that you run the initial clone command to put your container into an ephemeral clone state. You would then modify the container in some fashion, test, etc. When you where done with that iteration you would run the clone command again, losing all the changes you did to the container, replacing it with a new clean cloned copy of your original container. RRP (Rinse, Repeat, Profit)
198
+ In order to use the ephemeral cloning in LXC, we first need to put our container or containers into an ephemeral mode. This allows TestLab to do certain operations on the backend to prepare the container for ephemeral cloning. Then when you are finished, you can easily return the container to a persistent mode.
143
199
 
144
- We can also see the containers status reflects that it is a clone currently:
200
+ For example, to put the container into the ephemeral mode:
145
201
 
146
- $ tl container status -n server-www-1
147
- [TL] TestLab v0.6.1 Loaded
148
- +----------------------------------------------+
149
- | NODE_ID: vagrant |
150
- | ID: server-www-1 |
151
- | CLONE: true |
152
- | FQDN: server-www-1.default.zone |
153
- | STATE: running |
154
- | DISTRO: ubuntu |
155
- | RELEASE: precise |
156
- | INTERFACES: labnet:eth0:10.10.0.21/16 |
157
- | PROVISIONERS: Resolv/AptCacherNG/Apt/Shell |
158
- +----------------------------------------------+
202
+ $ tl container ephemeral -n chef-client
203
+ [TL] TestLab v1.1.0 Loaded
204
+ [TL] container chef-client ephemeral # Completed in 17.3453 seconds!
205
+ [TL] TestLab v1.1.0 Finished (17.8546 seconds)
159
206
 
160
- We can easily revert it back to a full container if we want to make "permanent" changes to it:
207
+ Now with our container in the ephemeral mode, we can run all of the normal container tasks against it with one simple caveat. When you offline the container and bring it back online, it will be reverted to the original state it was in before you put it into the ephemeral mode. The short of all this is, you can do what you will to the container, but the moment you bounce it (offline then online it) it reverts. This, as you can imagine, is extremely useful for developing applications and infrastructure as code.
161
208
 
162
- $ tl container up -n server-www-1
209
+ You can quickly revert that chef node back to it's previous state in the event the cookbook you are developing has wrecked the node. For web developers, imagine having a mysql server running in an ephemeral container; you can quickly roll back all database operations just by bouncing the container.
163
210
 
164
- We can even recycle it while it is in a cloned state:
211
+ This is effectively transactions for infrastructure.
165
212
 
166
- $ tl container recycle -n server-www-1
213
+ To put the container back into the default, persistent mode:
167
214
 
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):
215
+ $ tl container persistent -n chef-client
216
+ [TL] TestLab v1.1.0 Loaded
217
+ [TL] container chef-client persistent # Completed in 17.3692 seconds!
218
+ [TL] TestLab v1.1.0 Finished (17.8692 seconds)
169
219
 
170
- $ tl container provision -n server-www-1
171
220
 
172
221
  ## Network Routes
173
222
 
174
223
  TestLab will add network routes for any networks defined in the `Labfile` witch have the `TestLab::Provisioner::Route` provisioner class specified for them. This will allow you to directly interact with containers over the network. Here is an example of the routes added with the multi-network `Labfile`.
175
224
 
176
- $ tl network route show -n labnet
177
- [TL] TestLab v0.6.1 Loaded
225
+ $ tl network route show
226
+ [TL] TestLab v1.1.0 Loaded
178
227
  TestLab routes:
179
- 10.10.0.0 192.168.33.239 255.255.0.0 UG 0 0 0 vboxnet0
180
- 10.11.0.0 192.168.33.239 255.255.0.0 UG 0 0 0 vboxnet0
228
+ 172.16.0.0 192.168.33.2 255.255.255.0 UG 0 0 0 vboxnet0
229
+ [TL] TestLab v1.1.0 Finished (0.5063 seconds)
181
230
 
182
231
  These routes can be manually manipulated as well (regardless of if you have specified the `TestLab::Provisioner::Route` provisioner class for the networks via the `Labfile`):
183
232
 
@@ -186,9 +235,9 @@ These routes can be manually manipulated as well (regardless of if you have spec
186
235
  route - Manage routes
187
236
 
188
237
  SYNOPSIS
189
- tl [global options] network route [command options] add
190
- tl [global options] network route [command options] del
191
- tl [global options] network route [command options] show
238
+ tl [global options] network route add
239
+ tl [global options] network route del
240
+ tl [global options] network route show
192
241
 
193
242
  COMMANDS
194
243
  add - Add routes to lab networks
data/bin/tl CHANGED
@@ -28,7 +28,39 @@ include TestLab::Utility::Misc
28
28
  version TestLab::VERSION
29
29
 
30
30
  program_desc %(TestLab - A toolkit for building virtual computer labs)
31
- # program_long_desc %(Program Long Description)
31
+ program_long_desc <<-EOF
32
+ TestLab is based around the abstraction of three main components: nodes,
33
+ networks and containers. Nodes represent a system (bare-metal or virtualized)
34
+ that hosts containers. Networks repesent a Linux bridge on a node. Containers
35
+ simply represent a Linux Container (LXC) running on its parent node which is
36
+ typically connected to a network on the node.
37
+
38
+ In addition to the core component abstractions, TestLab shares a series of core
39
+ tasks that are universal across all of the components. These are create and
40
+ destroy, up and down, provision and deprovision. Several other core tasks,
41
+ such as build, demolish, recycle and bounce encapsulate the previously mentioned
42
+ tasks and simply act as convenience tasks.
43
+
44
+ You can execute almost all of the tasks against the entire lab, or individual
45
+ lab components.
46
+
47
+ When building a lab from scratch, you will typically run 'tl build'. To
48
+ breakdown your lab, destroying all the components, you will typically run
49
+ 'tl demolish'. If you want to re-build the lab you can run 'tl recycle' which
50
+ will run the demolish task followed by the build task against all the lab
51
+ components. If you want to power-cycle the entire lab you can run 'tl bounce'
52
+ which will run the down task followed by the up task against all the lab
53
+ components. Again these tasks can be run against the lab as a whole or
54
+ individual components.
55
+
56
+ You can view the status of the entire lab using 'tl status', or view the status
57
+ of individual components using 'tl node status', 'tl network status' or
58
+ 'tl container status'.
59
+
60
+ You can easily get help for any of the component tasks using the syntax
61
+ 'tl help <component>'. This can be extended to the following syntax
62
+ 'tl help <task>' or 'tl help <component> <task>' for more in-depth help.
63
+ EOF
32
64
 
33
65
  sort_help :manually
34
66
  default_command :help
@@ -14,14 +14,26 @@ When /^I down the containers with "([^"]*)"$/ do |app_name|
14
14
  container_cmd(app_name, %W(down -n test-server))
15
15
  end
16
16
 
17
- When /^I clone the containers with "([^"]*)"$/ do |app_name|
18
- container_cmd(app_name, %W(clone -n test-server))
17
+ When /^I put the containers in a ephemeral state with "([^"]*)"$/ do |app_name|
18
+ container_cmd(app_name, %W(ephemeral -n test-server))
19
+ end
20
+
21
+ When /^I put the containers in a persistent state with "([^"]*)"$/ do |app_name|
22
+ container_cmd(app_name, %W(persistent -n test-server))
19
23
  end
20
24
 
21
25
  When /^I build the containers with "([^"]*)"$/ do |app_name|
22
26
  container_cmd(app_name, %W(build -n test-server))
23
27
  end
24
28
 
29
+ When /^I bounce the containers with "([^"]*)"$/ do |app_name|
30
+ container_cmd(app_name, %W(bounce -n test-server))
31
+ end
32
+
33
+ When /^I recycle the containers with "([^"]*)"$/ do |app_name|
34
+ container_cmd(app_name, %W(recycle -n test-server))
35
+ end
36
+
25
37
  When /^I export the containers with "([^"]*)"$/ do |app_name|
26
38
  container_cmd(app_name, %W(export -n test-server --output=/tmp/test-server.sc))
27
39
  end
@@ -39,21 +39,52 @@ Feature: TestLab command-line
39
39
  Scenario: TestLab clone
40
40
  When I build the lab with "tl"
41
41
  Then the exit status should be 0
42
- When I clone the containers with "tl"
42
+
43
+ When I put the containers in a ephemeral state with "tl"
43
44
  Then the exit status should be 0
44
- When I build the containers with "tl"
45
+
46
+ When I bounce the containers with "tl"
45
47
  Then the exit status should be 0
46
- When I clone the containers with "tl"
48
+
49
+ When I bounce the containers with "tl"
47
50
  Then the exit status should be 0
51
+
48
52
  When I build the containers with "tl"
49
53
  Then the exit status should be 0
50
- When I down the containers with "tl"
54
+
55
+ When I bounce the containers with "tl"
56
+ Then the exit status should be 0
57
+
58
+ When I recycle the containers with "tl"
59
+ Then the exit status should be 0
60
+
61
+ When I bounce the containers with "tl"
62
+ Then the exit status should be 0
63
+
64
+ When I export the containers with "tl"
65
+ Then the exit status should be 1
66
+
67
+ When I put the containers in a persistent state with "tl"
68
+ Then the exit status should be 0
69
+
70
+ When I bounce the containers with "tl"
51
71
  Then the exit status should be 0
52
- When I up the containers with "tl"
72
+
73
+ When I bounce the containers with "tl"
53
74
  Then the exit status should be 0
75
+
54
76
  When I build the containers with "tl"
55
77
  Then the exit status should be 0
56
78
 
79
+ When I bounce the containers with "tl"
80
+ Then the exit status should be 0
81
+
82
+ When I recycle the containers with "tl"
83
+ Then the exit status should be 0
84
+
85
+ When I bounce the containers with "tl"
86
+ Then the exit status should be 0
87
+
57
88
 
58
89
  Scenario: TestLab Demolish
59
90
  When I demolish the lab with "tl"
@@ -99,42 +99,28 @@ EOF
99
99
  end
100
100
  end
101
101
 
102
- # CONTAINER RECYCLE
103
- ####################
104
- c.desc 'Recycle containers'
105
- c.long_desc <<-EOF
106
- Recycles a container. The container is taken through a series of state changes to ensure it is pristine.
102
+ # CONTAINER EPHEMERAL
103
+ ######################
104
+ c.desc 'Enable ephemeral mode for containers'
105
+ c.long_desc 'Put the container into a ephemeral clone state.'
107
106
 
108
- The container is cycled in this order:
109
-
110
- Deprovision -> Down -> Destroy -> Create -> Up -> Provision
111
- EOF
112
- c.command :recycle do |recycle|
113
- recycle.action do |global_options, options, args|
107
+ c.command :ephemeral do |ephemeral|
108
+ ephemeral.action do |global_options, options, args|
114
109
  iterate_objects_by_name(options[:name], TestLab::Container) do |container|
115
- container.deprovision
116
- container.down
117
- container.destroy
118
-
119
- container.create
120
- container.up
121
- container.provision
110
+ container.ephemeral
122
111
  end
123
112
  end
124
113
  end
125
114
 
126
- # CONTAINER CLONE
127
- ##################
128
- c.desc 'Clone containers'
129
- c.long_desc <<-EOF
130
- An ephemeral copy of the container is started.
115
+ # CONTAINER PERSISTENT
116
+ #######################
117
+ c.desc 'Enable persistent mode for containers'
118
+ c.long_desc 'Put the container into a persistent state.'
131
119
 
132
- NOTE: There is a small delay incured during the first clone operation.
133
- EOF
134
- c.command :clone do |clone|
135
- clone.action do |global_options, options, args|
120
+ c.command :persistent do |persistent|
121
+ persistent.action do |global_options, options, args|
136
122
  iterate_objects_by_name(options[:name], TestLab::Container) do |container|
137
- container.clone
123
+ container.persistent
138
124
  end
139
125
  end
140
126
  end
@@ -18,6 +18,86 @@
18
18
  #
19
19
  ################################################################################
20
20
 
21
+ # LAB BUILD
22
+ ############
23
+ desc 'Build the lab (create->up->provision)'
24
+ long_desc <<-EOF
25
+ Attempts to build the defined lab. TestLab will attempt to create, online and provision the lab components.
26
+
27
+ The components are built in the following order:
28
+
29
+ Nodes -> Networks -> Containers
30
+
31
+ TestLab will then attempt to build the components, executing the following tasks for each:
32
+
33
+ Create -> Up -> Provision
34
+ EOF
35
+ command :build do |build|
36
+ build.action do |global_options,options,args|
37
+ @testlab.build
38
+ end
39
+ end
40
+
41
+ # LAB DEMOLISH
42
+ ###############
43
+ desc 'Demolish the lab (deprovision->down->destroy)'
44
+ long_desc <<-EOF
45
+ Attempts to demolish the defined lab. TestLab will attempt to deprovision, offline and destroy the lab components.
46
+
47
+ The components are demolished in the following order:
48
+
49
+ Containers -> Networks -> Nodes
50
+
51
+ TestLab will then attempt to demolish the components, executing the following tasks for each:
52
+
53
+ Deprovision -> Down -> Destroy
54
+ EOF
55
+ command :demolish do |demolish|
56
+ demolish.action do |global_options,options,args|
57
+ @testlab.demolish
58
+ end
59
+ end
60
+
61
+ # LAB BOUNCE
62
+ #############
63
+ desc 'Bounce the lab (down->up)'
64
+ long_desc <<-EOF
65
+ Attempts to bounce the lab. TestLab will attempt to offline, then online the lab components.
66
+
67
+ The components are offlined in the following order:
68
+
69
+ Containers -> Networks -> Nodes
70
+
71
+ Then components are onlined in the following order:
72
+
73
+ Nodes -> Networks -> Containers
74
+ EOF
75
+ command :bounce do |bounce|
76
+ bounce.action do |global_options,options,args|
77
+ @testlab.bounce
78
+ end
79
+ end
80
+
81
+ # LAB RECYCLE
82
+ ##############
83
+ desc 'Recycle the lab (demolish->build)'
84
+ long_desc <<-EOF
85
+ Attempts to recycle the lab. TestLab will attempt to demolish, then build the lab components.
86
+
87
+ The components are demolished in the following order:
88
+
89
+ Containers -> Networks -> Nodes
90
+
91
+ Then components are built in the following order:
92
+
93
+ Nodes -> Networks -> Containers
94
+ EOF
95
+ command :recycle do |recycle|
96
+ recycle.action do |global_options,options,args|
97
+ @testlab.recycle
98
+ end
99
+ end
100
+
21
101
  # LAB CREATE
22
102
  #############
23
103
  desc 'Create the lab components'
@@ -114,46 +194,6 @@ command :deprovision do |deprovision|
114
194
  end
115
195
  end
116
196
 
117
- # LAB BUILD
118
- ############
119
- desc 'Build the lab'
120
- long_desc <<-EOF
121
- Attempts to build the defined lab. TestLab will attempt to create, online and provision the lab components.
122
-
123
- The components are built in the following order:
124
-
125
- Nodes -> Networks -> Containers
126
-
127
- TestLab will then attempt to build the components, executing the following tasks for each:
128
-
129
- Create -> Up -> Provision
130
- EOF
131
- command :build do |build|
132
- build.action do |global_options,options,args|
133
- @testlab.build
134
- end
135
- end
136
-
137
- # LAB DEMOLISH
138
- ###############
139
- desc 'Demolish the lab'
140
- long_desc <<-EOF
141
- Attempts to demolish the defined lab. TestLab will attempt to deprovision, offline and destroy the lab components.
142
-
143
- The components are demolished in the following order:
144
-
145
- Containers -> Networks -> Nodes
146
-
147
- TestLab will then attempt to demolish the components, executing the following tasks for each:
148
-
149
- Deprovision -> Down -> Destroy
150
- EOF
151
- command :demolish do |demolish|
152
- demolish.action do |global_options,options,args|
153
- @testlab.demolish
154
- end
155
- end
156
-
157
197
  # LAB STATUS
158
198
  #############
159
199
  desc 'Display the lab status'
@@ -15,6 +15,9 @@ class TestLab
15
15
  (self.node.state != :running) and return false
16
16
  (self.lxc.state != :not_created) and return false
17
17
 
18
+ # If we are in ephemeral mode do not attempt to create the container.
19
+ self.lxc_clone.exists? and return false
20
+
18
21
  please_wait(:ui => @ui, :message => format_object_action(self, 'Create', :green)) do
19
22
  configure
20
23
 
@@ -37,9 +40,11 @@ class TestLab
37
40
  (self.node.state != :running) and return false
38
41
  (self.lxc.state == :not_created) and return false
39
42
 
43
+ # If we are in ephemeral mode do not attempt to destroy the container.
44
+ self.lxc_clone.exists? and return false
45
+
40
46
  please_wait(:ui => @ui, :message => format_object_action(self, 'Destroy', :red)) do
41
47
  self.lxc.destroy(%(-f))
42
- self.lxc_clone.destroy(%(-f))
43
48
 
44
49
  do_provisioner_callbacks(self, :destroy, @ui)
45
50
  end
@@ -61,17 +66,28 @@ class TestLab
61
66
  please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
62
67
  configure
63
68
 
64
- # ensure our container is in "static" mode
65
- self.to_static
69
+ # Remove any existing ARP entries for our container from the node.
70
+ self.interfaces.each do |interface|
71
+ self.node.exec(%(sudo arp --verbose --delete #{interface.ip}), :ignore_exit_status => true)
72
+ end
66
73
 
67
- self.lxc.start(%(--daemon))
74
+ if self.lxc_clone.exists?
75
+ self.lxc_clone.start_ephemeral(clone_args)
76
+ else
77
+ self.lxc.start(%(--daemon))
78
+ end
68
79
 
69
80
  (self.lxc.state != :running) and raise ContainerError, "The container failed to online!"
70
81
 
71
- self.users.each do |user|
72
- user.provision
82
+ # If we are not in ephemeral mode we should attempt to provision our
83
+ # defined users.
84
+ if !self.lxc_clone.exists?
85
+ self.users.each do |user|
86
+ user.provision
87
+ end
73
88
  end
74
89
 
90
+ # Ensure the hostname is set
75
91
  self.exec(%(sudo hostname #{self.fqdn}))
76
92
 
77
93
  do_provisioner_callbacks(self, :up, @ui)
@@ -92,8 +108,23 @@ class TestLab
92
108
  (self.lxc.state != :running) and return false
93
109
 
94
110
  please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
111
+
95
112
  self.lxc.stop
96
113
 
114
+ # If we are in ephemeral mode...
115
+ if self.lxc_clone.exists?
116
+
117
+ # IMPORTANT NOTE:
118
+ #
119
+ # If we are using a non-memory backed COW filesystem for the
120
+ # ephemeral clones we should destroy the container.
121
+ #
122
+ # If we are using a memory backed COW filesystem for the ephemeral
123
+ # clones then it will be released when the container is stopped.
124
+
125
+ self.persist and self.lxc.destroy(%(-f))
126
+ end
127
+
97
128
  (self.lxc.state == :running) and raise ContainerError, "The container failed to offline!"
98
129
 
99
130
  do_provisioner_callbacks(self, :down, @ui)
@@ -3,22 +3,31 @@ class TestLab
3
3
 
4
4
  module Clone
5
5
 
6
- # Clone the container
6
+ # Put the container into an ephemeral state.
7
7
  #
8
- # Prepares the container, if needed, for ephemeral cloning and clones it.
8
+ # Prepares the container, if needed, for ephemeral cloning.
9
9
  #
10
10
  # @return [Boolean] True if successful.
11
- def clone
12
- @ui.logger.debug { "Container Clone: #{self.id}" }
11
+ def ephemeral
12
+ @ui.logger.debug { "Container Ephemeral: #{self.id}" }
13
13
 
14
- please_wait(:ui => @ui, :message => format_object_action(self, 'Clone', :yellow)) do
15
-
16
- # ensure our container is in "ephemeral" mode
14
+ please_wait(:ui => @ui, :message => format_object_action(self, 'Ephemeral', :yellow)) do
17
15
  self.to_ephemeral
16
+ end
17
+
18
+ true
19
+ end
18
20
 
19
- self.node.exec(%(sudo arp --verbose --delete #{self.ip}), :ignore_exit_status => true)
21
+ # Put the container into a persistent state.
22
+ #
23
+ # Prepares the container, if needed, for persistance.
24
+ #
25
+ # @return [Boolean] True if successful.
26
+ def persistent
27
+ @ui.logger.debug { "Container Persistent: #{self.id}" }
20
28
 
21
- self.lxc_clone.start_ephemeral(clone_args)
29
+ please_wait(:ui => @ui, :message => format_object_action(self, 'Persistent', :yellow)) do
30
+ self.to_static
22
31
  end
23
32
 
24
33
  true
@@ -13,6 +13,11 @@ class TestLab
13
13
 
14
14
  (self.lxc.state == :not_created) and return false
15
15
 
16
+ # Throw an exception if we are attempting to export a container in a
17
+ # ephemeral state.
18
+ self.lxc_clone.exists? and raise ContainerError, 'You can not export ephemeral containers!'
19
+
20
+ # Ensure the container is stopped before we attempt to export it.
16
21
  self.down
17
22
 
18
23
  export_tempfile = Tempfile.new('export')
@@ -57,6 +62,9 @@ EOF
57
62
  def import(local_file)
58
63
  @ui.logger.debug { "Container Import: #{self.id} " }
59
64
 
65
+ # Ensure we are not in ephemeral mode.
66
+ self.to_static
67
+
60
68
  self.down
61
69
  self.destroy
62
70
  self.create
@@ -82,7 +82,6 @@ class TestLab
82
82
  autoload :Generators, 'testlab/container/generators'
83
83
  autoload :Interface, 'testlab/container/interface'
84
84
  autoload :IO, 'testlab/container/io'
85
- autoload :Lifecycle, 'testlab/container/lifecycle'
86
85
  autoload :LXC, 'testlab/container/lxc'
87
86
  autoload :MethodMissing, 'testlab/container/method_missing'
88
87
  autoload :Provision, 'testlab/container/provision'
@@ -97,7 +96,6 @@ class TestLab
97
96
  include TestLab::Container::Generators
98
97
  include TestLab::Container::Interface
99
98
  include TestLab::Container::IO
100
- include TestLab::Container::Lifecycle
101
99
  include TestLab::Container::LXC
102
100
  include TestLab::Container::MethodMissing
103
101
  include TestLab::Container::Provision
@@ -109,6 +107,7 @@ class TestLab
109
107
  extend TestLab::Container::ClassMethods
110
108
 
111
109
  include TestLab::Support::Execution
110
+ include TestLab::Support::Lifecycle
112
111
 
113
112
  include TestLab::Utility::Misc
114
113
 
@@ -62,7 +62,7 @@ brctl delbr #{self.bridge}
62
62
  @ui.logger.debug { "Network Up: #{self.id} " }
63
63
 
64
64
  (self.node.state != :running) and return false
65
- (self.state == :running) and return false
65
+ # (self.state == :running) and return false
66
66
 
67
67
  please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
68
68
  self.node.bootstrap(<<-EOF, :ignore_exit_status => true)
@@ -81,7 +81,7 @@ ifconfig #{self.bridge} #{self.ip} netmask #{self.netmask} broadcast #{self.broa
81
81
  @ui.logger.debug { "Network Down: #{self.id} " }
82
82
 
83
83
  (self.node.state != :running) and return false
84
- (self.state != :running) and return false
84
+ # (self.state != :running) and return false
85
85
 
86
86
  please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
87
87
  self.node.bootstrap(<<-EOF, :ignore_exit_status => true)
@@ -13,18 +13,18 @@ class TestLab
13
13
  autoload :Actions, 'testlab/network/actions'
14
14
  autoload :Bind, 'testlab/network/bind'
15
15
  autoload :ClassMethods, 'testlab/network/class_methods'
16
- autoload :Lifecycle, 'testlab/network/lifecycle'
17
16
  autoload :Provision, 'testlab/network/provision'
18
17
  autoload :Status, 'testlab/network/status'
19
18
 
20
19
  include TestLab::Network::Actions
21
20
  include TestLab::Network::Bind
22
- include TestLab::Network::Lifecycle
23
21
  include TestLab::Network::Provision
24
22
  include TestLab::Network::Status
25
23
 
26
24
  extend TestLab::Network::ClassMethods
27
25
 
26
+ include TestLab::Support::Lifecycle
27
+
28
28
  include TestLab::Utility::Misc
29
29
 
30
30
  # Associations and Attributes
data/lib/testlab/node.rb CHANGED
@@ -12,7 +12,6 @@ class TestLab
12
12
  # Sub-Modules
13
13
  autoload :Actions, 'testlab/node/actions'
14
14
  autoload :ClassMethods, 'testlab/node/class_methods'
15
- autoload :Lifecycle, 'testlab/node/lifecycle'
16
15
  autoload :LXC, 'testlab/node/lxc'
17
16
  autoload :MethodMissing, 'testlab/node/method_missing'
18
17
  autoload :Provision, 'testlab/node/provision'
@@ -20,7 +19,6 @@ class TestLab
20
19
  autoload :Status, 'testlab/node/status'
21
20
 
22
21
  include TestLab::Node::Actions
23
- include TestLab::Node::Lifecycle
24
22
  include TestLab::Node::LXC
25
23
  include TestLab::Node::MethodMissing
26
24
  include TestLab::Node::Provision
@@ -30,6 +28,7 @@ class TestLab
30
28
  extend TestLab::Node::ClassMethods
31
29
 
32
30
  include TestLab::Support::Execution
31
+ include TestLab::Support::Lifecycle
33
32
 
34
33
  include TestLab::Utility::Misc
35
34
 
@@ -66,7 +65,7 @@ class TestLab
66
65
 
67
66
  def domain
68
67
  self.config[:bind] ||= Hash.new
69
- self.config[:bind][:domain]
68
+ self.config[:bind][:domain] ||= 'tld.invalid'
70
69
  end
71
70
 
72
71
  end
@@ -48,7 +48,7 @@ class TestLab
48
48
 
49
49
  # Bind: Container Up
50
50
  #
51
- # @param [TestLab::Node] node The container which just came online.
51
+ # @param [TestLab::Container] container The container which just came online.
52
52
  # @return [Boolean] True if successful.
53
53
  def on_container_up(container)
54
54
  @ui.logger.debug { "BIND Provisioner: Container #{container.id}" }
@@ -69,7 +69,6 @@ class TestLab
69
69
 
70
70
  true
71
71
  end
72
- alias :on_network_create :on_network_up
73
72
 
74
73
  # Builds the main bind configuration sections
75
74
  def build_bind_main_partial(file)
@@ -29,7 +29,6 @@ class TestLab
29
29
 
30
30
  node.bootstrap(ZTK::Template.render(provision_template, @config))
31
31
  end
32
- alias :on_node_up :on_node_provision
33
32
 
34
33
  private
35
34
 
@@ -21,20 +21,18 @@ class TestLab
21
21
  end
22
22
 
23
23
  # Route: Network Provision
24
- def on_network_provision(network)
24
+ def on_network_up(network)
25
25
  manage_route(:add, network)
26
26
 
27
27
  true
28
28
  end
29
- alias :on_network_up :on_network_provision
30
29
 
31
30
  # Route: Network Deprovision
32
- def on_network_deprovision(network)
31
+ def on_network_down(network)
33
32
  manage_route(:del, network)
34
33
 
35
34
  true
36
35
  end
37
- alias :on_network_down :on_network_deprovision
38
36
 
39
37
  private
40
38
 
@@ -0,0 +1,43 @@
1
+ class TestLab
2
+ module Support
3
+
4
+ module Lifecycle
5
+
6
+ # Build the object
7
+ def build
8
+ create
9
+ up
10
+ provision
11
+
12
+ true
13
+ end
14
+
15
+ # Demolish the object
16
+ def demolish
17
+ deprovision
18
+ down
19
+ destroy
20
+
21
+ true
22
+ end
23
+
24
+ # Recycle the object
25
+ def recycle
26
+ demolish
27
+ build
28
+
29
+ true
30
+ end
31
+
32
+ # Bounce the object
33
+ def bounce
34
+ down
35
+ up
36
+
37
+ true
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+ end
@@ -12,6 +12,7 @@ class TestLab
12
12
  # @author Zachary Patten <zachary AT jovelabs DOT com>
13
13
  module Support
14
14
  autoload :Execution, 'testlab/support/execution'
15
+ autoload :Lifecycle, 'testlab/support/lifecycle'
15
16
  end
16
17
 
17
18
  end
@@ -7,7 +7,7 @@ class TestLab
7
7
  module GLI
8
8
  require 'ztk'
9
9
 
10
- LAB_ACTION_ORDER = %W(build demolish create destroy up down provision deprovision).map(&:to_sym)
10
+ LAB_ACTION_ORDER = %W(build demolish recycle bounce create destroy up down provision deprovision).map(&:to_sym)
11
11
 
12
12
  LAB_ACTIONS = {
13
13
  :create => ["Initialize %s", "Attempts to create the <%= @component %>."],
@@ -16,19 +16,33 @@ class TestLab
16
16
  :down => ["Off-line %s", "Attempts to offline the <%= @component %>."],
17
17
  :provision => ["Provision %s", "Attempts to provision the <%= @component %>."],
18
18
  :deprovision => ["De-provision %s", "Attempts to deprovision the <%= @component %>."],
19
- :build => ["Build %s", <<-EOF],
19
+ :bounce => ["Bounce %s (down->up)", <<-EOF],
20
+ Attempts to bounce the <%= @component %>. TestLab will attempt to offline, then online the <%= @component %>.
21
+
22
+ The <%= @component %> are taken through the following states:
23
+
24
+ Current -> Down -> Up
25
+ EOF
26
+ :recycle => ["Recycle %s (demolish->build)", <<-EOF],
27
+ Attempts to recycle the <%= @component %>. TestLab will attempt to demolish, then build the <%= @component %>.
28
+
29
+ The <%= @component %> are taken through the following states:
30
+
31
+ Current -> Demolish -> Build
32
+ EOF
33
+ :build => ["Build %s (create->up->provision)", <<-EOF],
20
34
  Attempts to build the <%= @component %>. TestLab will attempt to create, online and provision the <%= @component %>.
21
35
 
22
36
  The <%= @component %> are taken through the following states:
23
37
 
24
- Create -> Up -> Provision
38
+ Current -> Create -> Up -> Provision
25
39
  EOF
26
- :demolish => ["Demolish %s", <<-EOF]
40
+ :demolish => ["Demolish %s (deprovision->down->destroy)", <<-EOF]
27
41
  Attempts to demolish the <%= @component %>. TestLab will attempt to deprovision, offline and destroy the <%= @component %>.
28
42
 
29
43
  The <%= @component %> are taken through the following states:
30
44
 
31
- Deprovision -> Down -> Destroy
45
+ Current -> Deprovision -> Down -> Destroy
32
46
  EOF
33
47
  }
34
48
 
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
6
6
  end
data/lib/testlab.rb CHANGED
@@ -322,6 +322,32 @@ class TestLab
322
322
  true
323
323
  end
324
324
 
325
+ # Test Lab Bounce
326
+ #
327
+ # Attempts to bounce our lab topology. This calls various methods on
328
+ # all of our nodes, networks and containers.
329
+ #
330
+ # @return [Boolean] True if successful.
331
+ def bounce
332
+ self.down
333
+ self.up
334
+
335
+ true
336
+ end
337
+
338
+ # Test Lab Recycle
339
+ #
340
+ # Attempts to recycle our lab topology. This calls various methods on
341
+ # all of our nodes, networks and containers.
342
+ #
343
+ # @return [Boolean] True if successful.
344
+ def recycle
345
+ self.demolish
346
+ self.build
347
+
348
+ true
349
+ end
350
+
325
351
  # Node Method Proxy
326
352
  #
327
353
  # Iterates all of the lab nodes, sending the supplied method name and arguments
@@ -151,7 +151,9 @@ describe TestLab::Container do
151
151
  subject.stub(:detect_arch) { "amd64" }
152
152
  subject.lxc.stub(:create) { true }
153
153
  subject.lxc.stub(:state) { :not_created }
154
+ subject.lxc_clone.stub(:exists?) { false }
154
155
  subject.node.ssh.stub(:exec)
156
+
155
157
  subject.create
156
158
  end
157
159
  end
@@ -162,7 +164,8 @@ describe TestLab::Container do
162
164
  subject.lxc.stub(:exists?) { true }
163
165
  subject.lxc.stub(:state) { :stopped }
164
166
  subject.lxc.stub(:destroy) { true }
165
- subject.lxc_clone.stub(:destroy) { true }
167
+ subject.lxc_clone.stub(:exists?) { false }
168
+
166
169
  subject.destroy
167
170
  end
168
171
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testlab
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-20 00:00:00.000000000 Z
12
+ date: 2013-07-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gli
@@ -245,7 +245,6 @@ files:
245
245
  - lib/testlab/container/generators.rb
246
246
  - lib/testlab/container/interface.rb
247
247
  - lib/testlab/container/io.rb
248
- - lib/testlab/container/lifecycle.rb
249
248
  - lib/testlab/container/lxc.rb
250
249
  - lib/testlab/container/method_missing.rb
251
250
  - lib/testlab/container/provision.rb
@@ -260,13 +259,11 @@ files:
260
259
  - lib/testlab/network/actions.rb
261
260
  - lib/testlab/network/bind.rb
262
261
  - lib/testlab/network/class_methods.rb
263
- - lib/testlab/network/lifecycle.rb
264
262
  - lib/testlab/network/provision.rb
265
263
  - lib/testlab/network/status.rb
266
264
  - lib/testlab/node.rb
267
265
  - lib/testlab/node/actions.rb
268
266
  - lib/testlab/node/class_methods.rb
269
- - lib/testlab/node/lifecycle.rb
270
267
  - lib/testlab/node/lxc.rb
271
268
  - lib/testlab/node/method_missing.rb
272
269
  - lib/testlab/node/provision.rb
@@ -306,6 +303,7 @@ files:
306
303
  - lib/testlab/provisioners/templates/resolv/resolv.conf.erb
307
304
  - lib/testlab/support.rb
308
305
  - lib/testlab/support/execution.rb
306
+ - lib/testlab/support/lifecycle.rb
309
307
  - lib/testlab/user.rb
310
308
  - lib/testlab/user/lifecycle.rb
311
309
  - lib/testlab/utility.rb
@@ -339,12 +337,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
339
337
  - - ! '>='
340
338
  - !ruby/object:Gem::Version
341
339
  version: '0'
340
+ segments:
341
+ - 0
342
+ hash: -4166259606909951281
342
343
  required_rubygems_version: !ruby/object:Gem::Requirement
343
344
  none: false
344
345
  requirements:
345
346
  - - ! '>='
346
347
  - !ruby/object:Gem::Version
347
348
  version: '0'
349
+ segments:
350
+ - 0
351
+ hash: -4166259606909951281
348
352
  requirements: []
349
353
  rubyforge_project:
350
354
  rubygems_version: 1.8.25
@@ -1,27 +0,0 @@
1
- class TestLab
2
- class Container
3
-
4
- module Lifecycle
5
-
6
- # Build the container
7
- def build
8
- self.create
9
- self.up
10
- self.provision
11
-
12
- true
13
- end
14
-
15
- # Demolish the container
16
- def demolish
17
- self.deprovision
18
- self.down
19
- self.destroy
20
-
21
- true
22
- end
23
-
24
- end
25
-
26
- end
27
- end
@@ -1,27 +0,0 @@
1
- class TestLab
2
- class Network
3
-
4
- module Lifecycle
5
-
6
- # Build the network
7
- def build
8
- self.create
9
- self.up
10
- self.provision
11
-
12
- true
13
- end
14
-
15
- # Demolish the network
16
- def demolish
17
- self.deprovision
18
- self.down
19
- self.destroy
20
-
21
- true
22
- end
23
-
24
- end
25
-
26
- end
27
- end
@@ -1,26 +0,0 @@
1
- class TestLab
2
- class Node
3
-
4
- module Lifecycle
5
-
6
- # Build the node
7
- def build
8
- self.create
9
- self.up
10
- self.provision
11
-
12
- true
13
- end
14
-
15
- # Demolish the node
16
- def demolish
17
- self.deprovision
18
- self.down
19
- self.destroy
20
-
21
- true
22
- end
23
-
24
- end
25
- end
26
- end