testlab 0.9.0 → 0.9.1
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/bin/tl +16 -4
- data/lib/commands/container.rb +36 -0
- data/lib/testlab/container/actions.rb +10 -6
- data/lib/testlab/container/io.rb +33 -3
- data/lib/testlab/container/lxc.rb +13 -1
- data/lib/testlab/version.rb +1 -1
- metadata +4 -4
data/bin/tl
CHANGED
@@ -61,6 +61,8 @@ arg_name 'path/to/directory'
|
|
61
61
|
flag [:c, :config]
|
62
62
|
|
63
63
|
pre do |global,command,options,args|
|
64
|
+
@testlab_start_time = Time.now.utc
|
65
|
+
|
64
66
|
(global[:verbose] == true) and (ENV['LOG_LEVEL'] = 'DEBUG')
|
65
67
|
|
66
68
|
log_file = File.join(global[:repo], "testlab-#{TestLab.hostname}.log")
|
@@ -97,14 +99,20 @@ pre do |global,command,options,args|
|
|
97
99
|
end
|
98
100
|
|
99
101
|
post do |global,command,options,args|
|
100
|
-
|
101
|
-
|
102
|
-
#
|
102
|
+
testlab_run_time = (Time.now.utc - @testlab_start_time)
|
103
|
+
|
104
|
+
message = format_message("TestLab v#{TestLab::VERSION} Finished (%0.4f seconds)".black.bold % testlab_run_time)
|
105
|
+
@testlab.ui.stdout.puts(message)
|
106
|
+
@testlab.ui.logger.info { message }
|
107
|
+
|
108
|
+
true
|
103
109
|
end
|
104
110
|
|
105
111
|
on_error do |exception|
|
112
|
+
testlab_run_time = (Time.now.utc - @testlab_start_time)
|
113
|
+
|
106
114
|
@ui.stderr.puts
|
107
|
-
@ui.stderr.puts(format_message(["ERROR:".red, exception.
|
115
|
+
@ui.stderr.puts(format_message(["ERROR:".red, exception.inspect.red.bold].join(' ')))
|
108
116
|
|
109
117
|
case exception
|
110
118
|
when GLI::BadCommandLine, GLI::UnknownCommand, GLI::UnknownCommandArgument, GLI::UnknownGlobalArgument then
|
@@ -121,6 +129,10 @@ on_error do |exception|
|
|
121
129
|
@logger.logdev.write("#{line}\n")
|
122
130
|
end
|
123
131
|
|
132
|
+
message = format_message("TestLab v#{TestLab::VERSION} Aborted (%0.4f seconds)".black.bold % testlab_run_time)
|
133
|
+
@testlab.ui.stderr.puts(message)
|
134
|
+
@testlab.ui.logger.info { message }
|
135
|
+
|
124
136
|
false
|
125
137
|
end
|
126
138
|
end
|
data/lib/commands/container.rb
CHANGED
@@ -84,6 +84,21 @@ EOF
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
# CONTAINER CONSOLE
|
88
|
+
####################
|
89
|
+
c.desc 'Container console'
|
90
|
+
c.command :console do |console|
|
91
|
+
|
92
|
+
console.action do |global_options, options, args|
|
93
|
+
help_now!('a name is required') if options[:name].nil?
|
94
|
+
|
95
|
+
container = @testlab.containers.select{ |n| n.id.to_sym == options[:name].to_sym }.first
|
96
|
+
container.nil? and raise TestLab::TestLabError, "We could not find the container you supplied!"
|
97
|
+
|
98
|
+
container.console
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
87
102
|
# CONTAINER RECYCLE
|
88
103
|
####################
|
89
104
|
c.desc 'Recycle containers'
|
@@ -124,6 +139,27 @@ EOF
|
|
124
139
|
end
|
125
140
|
end
|
126
141
|
|
142
|
+
# CONTAINER COPY
|
143
|
+
#################
|
144
|
+
c.desc 'Copy containers'
|
145
|
+
c.long_desc <<-EOF
|
146
|
+
Creates a copy of a container.
|
147
|
+
|
148
|
+
NOTE: This will result in the source container being stopped before the copy operation commences.
|
149
|
+
EOF
|
150
|
+
c.command :copy do |copy|
|
151
|
+
|
152
|
+
copy.desc %(The container ID we wish to copy the original container to.)
|
153
|
+
copy.arg_name %(container)
|
154
|
+
copy.flag [:t, :to]
|
155
|
+
|
156
|
+
copy.action do |global_options, options, args|
|
157
|
+
iterate_objects_by_name(options[:name], TestLab::Container) do |container|
|
158
|
+
container.copy(options[:to])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
127
163
|
# CONTAINER EXPORT
|
128
164
|
###################
|
129
165
|
c.desc 'Export containers'
|
@@ -10,7 +10,7 @@ class TestLab
|
|
10
10
|
#
|
11
11
|
# @return [Boolean] True if successful.
|
12
12
|
def create
|
13
|
-
@ui.logger.debug { "Container Create: #{self.id}
|
13
|
+
@ui.logger.debug { "Container Create: #{self.id}" }
|
14
14
|
|
15
15
|
(self.node.state != :running) and return false
|
16
16
|
(self.lxc.state != :not_created) and return false
|
@@ -30,7 +30,7 @@ class TestLab
|
|
30
30
|
#
|
31
31
|
# @return [Boolean] True if successful.
|
32
32
|
def destroy
|
33
|
-
@ui.logger.debug { "Container Destroy: #{self.id}
|
33
|
+
@ui.logger.debug { "Container Destroy: #{self.id}" }
|
34
34
|
|
35
35
|
(self.node.state != :running) and return false
|
36
36
|
(self.lxc.state == :not_created) and return false
|
@@ -49,7 +49,7 @@ class TestLab
|
|
49
49
|
#
|
50
50
|
# @return [Boolean] True if successful.
|
51
51
|
def up
|
52
|
-
@ui.logger.debug { "Container Up: #{self.id}
|
52
|
+
@ui.logger.debug { "Container Up: #{self.id}" }
|
53
53
|
|
54
54
|
(self.node.state != :running) and return false
|
55
55
|
(self.lxc.state == :running) and return false
|
@@ -68,6 +68,7 @@ class TestLab
|
|
68
68
|
user.setup
|
69
69
|
end
|
70
70
|
|
71
|
+
self.ssh.exec(%(sudo hostname #{self.fqdn}))
|
71
72
|
end
|
72
73
|
|
73
74
|
true
|
@@ -79,14 +80,13 @@ class TestLab
|
|
79
80
|
#
|
80
81
|
# @return [Boolean] True if successful.
|
81
82
|
def down
|
82
|
-
@ui.logger.debug { "Container Down: #{self.id}
|
83
|
+
@ui.logger.debug { "Container Down: #{self.id}" }
|
83
84
|
|
84
85
|
(self.node.state != :running) and return false
|
85
86
|
(self.lxc.state != :running) and return false
|
86
87
|
|
87
88
|
please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
|
88
89
|
self.lxc.stop
|
89
|
-
self.lxc.wait(:stopped)
|
90
90
|
|
91
91
|
(self.lxc.state == :running) and raise ContainerError, "The container failed to offline!"
|
92
92
|
end
|
@@ -112,7 +112,7 @@ class TestLab
|
|
112
112
|
ephemeral_arguments = Array.new
|
113
113
|
ephemeral_arguments << %W(-o #{self.lxc_clone.name} -n #{self.lxc.name} -d)
|
114
114
|
ephemeral_arguments << %W(--keep-data) if self.persist
|
115
|
-
ephemeral_arguments
|
115
|
+
ephemeral_arguments.flatten!.compact!
|
116
116
|
|
117
117
|
self.lxc_clone.start_ephemeral(ephemeral_arguments)
|
118
118
|
end
|
@@ -121,6 +121,10 @@ class TestLab
|
|
121
121
|
end
|
122
122
|
|
123
123
|
# Configure the container
|
124
|
+
#
|
125
|
+
# Configures the LXC subsystem for the container.
|
126
|
+
#
|
127
|
+
# @return [Boolean] True if successful.
|
124
128
|
def configure
|
125
129
|
self.domain ||= self.node.domain
|
126
130
|
self.arch ||= detect_arch
|
data/lib/testlab/container/io.rb
CHANGED
@@ -30,9 +30,11 @@ set -x
|
|
30
30
|
set -e
|
31
31
|
|
32
32
|
du -sh #{self.lxc.container_root}
|
33
|
+
|
33
34
|
cd #{self.lxc.container_root}
|
34
35
|
find #{root_fs_path} -depth -print0 | cpio -o0 | pbzip2 -#{compression} -vfczm#{PBZIP2_MEMORY} > #{remote_file}
|
35
36
|
chown ${SUDO_USER}:${SUDO_USER} #{remote_file}
|
37
|
+
|
36
38
|
ls -lah #{remote_file}
|
37
39
|
EOF
|
38
40
|
end
|
@@ -42,7 +44,9 @@ EOF
|
|
42
44
|
self.node.ssh.download(remote_file, local_file)
|
43
45
|
end
|
44
46
|
|
45
|
-
puts
|
47
|
+
@ui.stdout.puts
|
48
|
+
@ui.stdout.puts("Your shipping container is now exported and available at '#{local_file}'!".green.bold)
|
49
|
+
@ui.stdout.puts
|
46
50
|
|
47
51
|
true
|
48
52
|
end
|
@@ -76,14 +80,40 @@ set -x
|
|
76
80
|
set -e
|
77
81
|
|
78
82
|
ls -lah #{remote_file}
|
83
|
+
|
84
|
+
rm -rf #{self.lxc.fs_root}
|
79
85
|
cd #{self.lxc.container_root}
|
80
|
-
rm -rf #{root_fs_path}
|
81
86
|
pbzip2 -vdcm#{PBZIP2_MEMORY} #{remote_file} | cpio -uid && rm -fv #{remote_file}
|
87
|
+
|
82
88
|
du -sh #{self.lxc.container_root}
|
83
89
|
EOF
|
84
90
|
end
|
85
91
|
|
86
|
-
puts
|
92
|
+
@ui.stdout.puts
|
93
|
+
@ui.stdout.puts("Your shipping container is now imported and available for use!".green.bold)
|
94
|
+
@ui.stdout.puts
|
95
|
+
|
96
|
+
true
|
97
|
+
end
|
98
|
+
|
99
|
+
# Copy the container
|
100
|
+
#
|
101
|
+
# Duplicates this container under another container definition.
|
102
|
+
#
|
103
|
+
# @return [Boolean] True if successful.
|
104
|
+
def copy(to_name)
|
105
|
+
@ui.logger.debug { "Container Copy: #{self.id}" }
|
106
|
+
|
107
|
+
to_container = self.node.containers.select{ |c| c.id.to_sym == to_name.to_sym }.first
|
108
|
+
to_container.nil? and raise ContainerError, "We could not locate the target container!"
|
109
|
+
|
110
|
+
to_container.demolish
|
111
|
+
to_container.create
|
112
|
+
|
113
|
+
please_wait(:ui => @ui, :message => format_object_action(self, 'Copy', :yellow)) do
|
114
|
+
self.node.ssh.exec(%(sudo rm -rf #{to_container.lxc.fs_root}))
|
115
|
+
self.node.ssh.exec(%(sudo rsync -a #{self.lxc.fs_root} #{to_container.lxc.container_root}))
|
116
|
+
end
|
87
117
|
|
88
118
|
true
|
89
119
|
end
|
@@ -25,6 +25,18 @@ class TestLab
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
# Container Console
|
29
|
+
#
|
30
|
+
# Opens an LXC console into the container.
|
31
|
+
#
|
32
|
+
# This command will replace the current process with an SSH session that
|
33
|
+
# will execute the appropriate LXC console command on the parent node of
|
34
|
+
# this container.
|
35
|
+
def console
|
36
|
+
@ui.stdout.puts("Press CTRL-A Q to exit the console. (CTRL-A CTRL-A to enter a CTRL-A itself)".red.bold)
|
37
|
+
self.node.ssh.console(%(-t 'sudo lxc-console -n #{self.id}'))
|
38
|
+
end
|
39
|
+
|
28
40
|
# LXC::Container object
|
29
41
|
#
|
30
42
|
# Returns a *LXC::Container* class instance configured for this container.
|
@@ -142,8 +154,8 @@ class TestLab
|
|
142
154
|
def build_lxc_config(lxc_config)
|
143
155
|
lxc_config.clear
|
144
156
|
|
145
|
-
lxc_config['lxc.utsname'] = self.fqdn
|
146
157
|
lxc_config['lxc.arch'] = self.arch
|
158
|
+
lxc_config['lxc.utsname'] = self.fqdn
|
147
159
|
lxc_config.networks = build_lxc_network_conf(self.interfaces)
|
148
160
|
|
149
161
|
lxc_config.save
|
data/lib/testlab/version.rb
CHANGED
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: 0.9.
|
4
|
+
version: 0.9.1
|
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-
|
12
|
+
date: 2013-07-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gli
|
@@ -331,7 +331,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
331
331
|
version: '0'
|
332
332
|
segments:
|
333
333
|
- 0
|
334
|
-
hash:
|
334
|
+
hash: 4125715587205282977
|
335
335
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
336
336
|
none: false
|
337
337
|
requirements:
|
@@ -340,7 +340,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
340
340
|
version: '0'
|
341
341
|
segments:
|
342
342
|
- 0
|
343
|
-
hash:
|
343
|
+
hash: 4125715587205282977
|
344
344
|
requirements: []
|
345
345
|
rubyforge_project:
|
346
346
|
rubygems_version: 1.8.25
|