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 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