testlab 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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
- # Post logic here
101
- # Use skips_post before a command to skip this
102
- # block on that command only
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.message.red.bold].join(' ')))
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
@@ -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 = ephemeral_arguments.flatten.compact
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
@@ -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("Your shipping container is now exported and available at '#{local_file}'!")
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("Your shipping container is now imported and available for use!")
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
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "0.9.0"
4
+ VERSION = "0.9.1"
5
5
  end
6
6
  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: 0.9.0
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-11 00:00:00.000000000 Z
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: 2591373511513958371
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: 2591373511513958371
343
+ hash: 4125715587205282977
344
344
  requirements: []
345
345
  rubyforge_project:
346
346
  rubygems_version: 1.8.25