testlab 0.4.0 → 0.4.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/.travis.yml CHANGED
@@ -2,13 +2,10 @@ language: ruby
2
2
 
3
3
  rvm:
4
4
  - ree
5
+ - 1.8.7
5
6
  - 1.9.2
6
7
  - 1.9.3
7
8
  - 2.0.0
8
9
 
9
10
  notifications:
10
11
  irc: "irc.freenode.net#jovelabs"
11
-
12
- matrix:
13
- allow_failures:
14
- - rvm: ree
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem "json" if (RUBY_VERSION == "1.8.7")
4
+
3
5
  gemspec
data/README.md CHANGED
@@ -34,6 +34,14 @@ For more information see the TestLab Documentation, `testlab-repo`, command-line
34
34
 
35
35
  * See the `testlab-repo` - https://github.com/zpatten/testlab-repo
36
36
 
37
+ # RUBIES TESTED AGAINST
38
+
39
+ * Ruby 1.8.7 (REE)
40
+ * Ruby 1.8.7 (MBARI)
41
+ * Ruby 1.9.2
42
+ * Ruby 1.9.3
43
+ * Ruby 2.0.0
44
+
37
45
  # RESOURCES
38
46
 
39
47
  IRC:
@@ -26,6 +26,18 @@ class TestLab
26
26
  self.lxc.config.save
27
27
 
28
28
  self.lxc.create(*create_args)
29
+
30
+ # TODO: This needs to really go somewhere else:
31
+ home_dir = ((self.node.user == "root") ? %(/root) : %(/home/#{self.node.user}))
32
+ container_home_dir = File.join(self.lxc.fs_root, "/home/ubuntu")
33
+
34
+ home_authkeys = File.join(home_dir, %(.ssh), %(authorized_keys))
35
+ container_authkeys = File.join(container_home_dir, %(.ssh), %(authorized_keys))
36
+
37
+ self.node.ssh.exec(%(mkdir -pv #{File.join(container_home_dir, %(.ssh))}))
38
+ self.node.ssh.exec(%(sudo cp -v #{home_authkeys} #{container_authkeys}))
39
+ self.node.ssh.exec(%(sudo chown -v 1000:1000 #{container_authkeys}))
40
+ self.node.ssh.exec(%(sudo chmod -v 644 #{container_authkeys}))
29
41
  end
30
42
 
31
43
  true
@@ -54,13 +66,16 @@ class TestLab
54
66
  def up
55
67
  @ui.logger.debug { "Container Up: #{self.id} " }
56
68
 
57
- (self.lxc.state == :not_created) and raise ContainerError, "We can not online a non-existant container!"
69
+ (self.lxc.state == :not_created) and return false #raise ContainerError, "We can not online a non-existant container!"
58
70
 
59
71
  please_wait(:ui => @ui, :message => format_object_action(self, 'Up', :green)) do
60
72
  self.lxc.start
61
73
  self.lxc.wait(:running)
62
74
 
63
75
  (self.lxc.state != :running) and raise ContainerError, "The container failed to online!"
76
+
77
+ # TODO: This needs to really go somewhere else:
78
+ self.lxc.attach(%(/bin/bash -c 'grep "sudo\tALL=\(ALL:ALL\) ALL" /etc/sudoers && sed -i "s/sudo\tALL=\(ALL:ALL\) ALL/sudo\tALL=\(ALL:ALL\) NOPASSWD: ALL/" /etc/sudoers'))
64
79
  end
65
80
 
66
81
  true
@@ -74,7 +89,7 @@ class TestLab
74
89
  def down
75
90
  @ui.logger.debug { "Container Down: #{self.id} " }
76
91
 
77
- (self.lxc.state == :not_created) and raise ContainerError, "We can not offline a non-existant container!"
92
+ (self.lxc.state == :not_created) and return false # raise ContainerError, "We can not offline a non-existant container!"
78
93
 
79
94
  please_wait(:ui => @ui, :message => format_object_action(self, 'Down', :red)) do
80
95
  self.lxc.stop
@@ -16,10 +16,11 @@ class TestLab
16
16
 
17
17
  ZTK::RescueRetry.try(:tries => 3, :on => ContainerError) do
18
18
  tempfile = Tempfile.new("bootstrap")
19
- self.node.ssh.file(:target => File.join(self.lxc.fs_root, tempfile.path), :chmod => '0777', :chown => 'root:root') do |file|
19
+ remote_tempfile = File.join("/tmp", File.basename(tempfile.path))
20
+ self.node.ssh.file(:target => File.join(self.lxc.fs_root, remote_tempfile), :chmod => '0777', :chown => 'root:root') do |file|
20
21
  file.puts(content)
21
22
  end
22
- output = self.lxc.attach(%(/bin/bash), tempfile.path)
23
+ output = self.lxc.attach(%(/bin/bash), remote_tempfile)
23
24
  if output =~ /No such file or directory/
24
25
  raise ContainerError, "We could not find the bootstrap file!"
25
26
  end
@@ -9,16 +9,31 @@ class TestLab
9
9
 
10
10
  self.create
11
11
  self.up
12
+ self.route and route(:add)
12
13
  end
13
14
 
14
15
  # Network Teardown
15
16
  def teardown
16
17
  @ui.logger.debug { "Network Teardown: #{self.id} " }
17
18
 
19
+ self.route and route(:del)
18
20
  self.down
19
21
  self.destroy
20
22
  end
21
23
 
24
+ def route(action)
25
+ self.networks.each do |network|
26
+ command = ZTK::Command.new(:ui => @ui, :silence => true, :ignore_exit_status => true)
27
+
28
+ case RUBY_PLATFORM
29
+ when /darwin/ then
30
+ command.exec(%(sudo route #{action} -net #{TestLab::Utility.network(network.address)} #{network.node.ip} #{TestLab::Utility.netmask(network.address)}))
31
+ when /linux/ then
32
+ command.exec(%(sudo route #{action} -net #{TestLab::Utility.network(network.address)} netmask #{TestLab::Utility.netmask(network.address)} gw #{network.node.ip}))
33
+ end
34
+ end
35
+ end
36
+
22
37
  end
23
38
 
24
39
  end
@@ -31,6 +31,7 @@ class TestLab
31
31
 
32
32
  attribute :address
33
33
  attribute :bridge
34
+ attribute :route, :default => false
34
35
 
35
36
  attribute :config
36
37
 
@@ -26,23 +26,12 @@ class TestLab
26
26
  self.ssh.bootstrap(ZTK::Template.render(node_setup_template))
27
27
  end
28
28
 
29
- def route_setup(action)
30
- self.networks.each do |network|
31
- command = ZTK::Command.new(:silence => true, :ignore_exit_status => true)
32
- command.exec(%(sudo route #{action} -net #{TestLab::Utility.network(network.address)} netmask #{TestLab::Utility.netmask(network.address)} gw #{network.node.ip}))
33
- end
34
- end
35
-
36
29
  # Setup the node.
37
30
  def setup
38
31
  @ui.logger.debug { "Node Setup: #{self.id} " }
39
32
 
40
33
  please_wait(:ui => @ui, :message => format_object_action(self, 'Setup', :green)) do
41
34
 
42
- if (self.route == true)
43
- route_setup(:add)
44
- end
45
-
46
35
  node_setup
47
36
 
48
37
  if self.components.include?('resolv')
@@ -70,10 +59,7 @@ class TestLab
70
59
  call_collections([self.containers, self.networks], :teardown)
71
60
 
72
61
  please_wait(:ui => @ui, :message => format_object_action(self, 'Teardown', :red)) do
73
-
74
- if (self.route == true)
75
- route_setup(:del)
76
- end
62
+ # NOOP
77
63
  end
78
64
 
79
65
  true
@@ -12,6 +12,7 @@ class TestLab
12
12
  :instance_id => @provider.instance_id,
13
13
  :state => @provider.state,
14
14
  :user => @provider.user,
15
+ :identity => @provider.identity,
15
16
  :ip => @provider.ip,
16
17
  :port => @provider.port,
17
18
  :provider => @provider.class,
@@ -15,4 +15,3 @@ sysctl net.ipv4.ip_forward | grep "net.ipv4.ip_forward = 1" || sysctl -w net.ipv
15
15
 
16
16
  # Install an iptable NAT rule
17
17
  iptables -t nat --list -v | grep "MASQUERADE all -- any eth0 anywhere anywhere" || iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
18
-
data/lib/testlab/node.rb CHANGED
@@ -34,15 +34,14 @@ class TestLab
34
34
  include TestLab::Utility::Misc
35
35
 
36
36
  # Associations and Attributes
37
- belongs_to :labfile, :class_name => 'TestLab::Lab'
37
+ belongs_to :labfile, :class_name => 'TestLab::Labfile'
38
38
 
39
39
  has_many :containers, :class_name => 'TestLab::Container'
40
40
  has_many :networks, :class_name => 'TestLab::Network'
41
41
 
42
42
  attribute :provider
43
- attribute :config
43
+ attribute :config, :default => Hash.new
44
44
  attribute :components, :default => Array.new
45
- attribute :route, :default => false
46
45
 
47
46
 
48
47
  def initialize(*args)
@@ -7,7 +7,7 @@ class TestLab
7
7
  #
8
8
  # @author Zachary Patten <zachary AT jovelabs DOT com>
9
9
  class Provider
10
- PROXY_METHODS = %w(instance_id state user ip port create destroy up down reload status alive? dead? exists?).map(&:to_sym)
10
+ PROXY_METHODS = %w(instance_id state user identity ip port create destroy up down reload status alive? dead? exists?).map(&:to_sym)
11
11
 
12
12
  autoload :AWS, 'testlab/providers/aws'
13
13
  autoload :Local, 'testlab/providers/local'
@@ -174,7 +174,7 @@ class TestLab
174
174
  command = TestLab.build_command_line("vagrant", *args)
175
175
  @ui.logger.debug { "command == #{command.inspect}" }
176
176
 
177
- ZTK::Command.new(:ui => @ui).exec(command, :silence => true)
177
+ ZTK::Command.new(:ui => @ui, :silence => true).exec(command)
178
178
  end
179
179
 
180
180
  def render_vagrantfile
@@ -191,15 +191,10 @@ class TestLab
191
191
  }
192
192
 
193
193
  vagrantfile_template = File.join(TestLab::Provider.template_dir, "vagrant", "Vagrantfile.erb")
194
- vagrantfile = File.join(@config[:repo], "Vagrantfile")
194
+ vagrantfile = File.join(@config[:vagrant][:file], "Vagrantfile")
195
195
 
196
- # UGLY; but it makes it run under 1.9.2
197
- if RUBY_VERSION < "1.9.3"
198
- File.open(vagrantfile, 'w') do |file|
199
- file.puts(ZTK::Template.render(vagrantfile_template, context))
200
- end
201
- else
202
- IO.write(vagrantfile, ZTK::Template.render(vagrantfile_template, context))
196
+ File.open(vagrantfile, 'w') do |file|
197
+ file.puts(ZTK::Template.render(vagrantfile_template, context))
203
198
  end
204
199
  end
205
200
 
@@ -40,7 +40,8 @@ class TestLab
40
40
  :default_password => "p@ssw01d",
41
41
  :user => ENV['USER'],
42
42
  :hostname_short => container.id,
43
- :hostname_full => container.fqdn
43
+ :hostname_full => container.fqdn,
44
+ :omnibus_version => omnibus_version
44
45
  }).merge!(@config)
45
46
  container.bootstrap(ZTK::Template.render(omnibus_template, config))
46
47
  end
@@ -60,7 +61,8 @@ class TestLab
60
61
 
61
62
  def build_chef_solo_10_attributes(container)
62
63
  {
63
- "chef-server" => {
64
+ "chef_server" => {
65
+ "url" => "https://#{container.fqdn}",
64
66
  "webui_enabled" => true
65
67
  },
66
68
  "run_list" => %w(recipe[chef-server::rubygems-install] recipe[chef-server::apache-proxy])
@@ -109,6 +111,14 @@ class TestLab
109
111
  end
110
112
  end
111
113
 
114
+ def omnibus_version
115
+ if (@config[:version].to_f == 0.1)
116
+ "10.12.0"
117
+ else
118
+ @config[:version]
119
+ end
120
+ end
121
+
112
122
  end
113
123
 
114
124
  end
@@ -7,11 +7,11 @@ CHEF_SOLO_ROOT="/tmp/chef-solo"
7
7
  KNIFE_CONFIG_EXP_FILE="/tmp/knife-config.exp"
8
8
  export DEBIAN_FRONTEND CHEF_SOLO_ROOT KNIFE_CONFIG_EXP_FILE
9
9
 
10
- mkdir -p /tmp/chef-solo/
10
+ mkdir -p ${CHEF_SOLO_ROOT}
11
11
  cd ${CHEF_SOLO_ROOT}
12
12
 
13
13
  apt-get -y --force-yes update
14
- apt-get -y --force-yes install build-essential expect wget curl
14
+ apt-get -y --force-yes install build-essential expect wget curl libgecode-dev
15
15
 
16
16
  mkdir -pv /etc/chef /var/log/chef ${HOME}/.chef
17
17
 
@@ -25,8 +25,8 @@ cat <<EOF | tee ${CHEF_SOLO_ROOT}/attributes.json
25
25
  <%= @chef_solo_attributes.to_json %>
26
26
  EOF
27
27
 
28
- curl -L https://www.opscode.com/chef/install.sh | bash
29
- # bash install.sh -v <%= @version %>
28
+ wget -v https://www.opscode.com/chef/install.sh
29
+ bash install.sh -v <%= @omnibus_version %>
30
30
  <% if (@chef_pre_11 == false) -%>
31
31
 
32
32
  mkdir -pv /var/chef/cache ${CHEF_SOLO_ROOT}/cookbooks/chef-server
@@ -49,11 +49,10 @@ EOF
49
49
 
50
50
  gem install bundler --no-ri --no-rdoc
51
51
  bundle install --standalone --path vendor/bundle --binstubs
52
- mv -v ${CHEF_SOLO_ROOT}/cookbooks ${CHEF_SOLO_ROOT}/site-cookbooks
53
52
  bin/berks install --path ${CHEF_SOLO_ROOT}/cookbooks/
54
53
  <% end -%>
55
54
 
56
- chef-solo --config /etc/chef/solo.rb --json-attributes ${CHEF_SOLO_ROOT}/attributes.json --logfile /var/log/chef/chef-solo.log --log_level debug
55
+ PATH=./bin/:$PATH chef-solo --config /etc/chef/solo.rb --json-attributes ${CHEF_SOLO_ROOT}/attributes.json --logfile /var/log/chef/chef-solo.log --log_level debug
57
56
  <% if (@chef_pre_11 == false) -%>
58
57
 
59
58
  cat << EOF | tee /etc/chef-server/chef-server.rb
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.1"
5
5
  end
6
6
  end
data/lib/testlab.rb CHANGED
@@ -22,7 +22,8 @@ require 'testlab/monkeys'
22
22
  # EOF
23
23
  #
24
24
  # config Hash[
25
- # :domain => "default.zone"
25
+ # :domain => "default.zone",
26
+ # :repo => File.join(ENV['HOME'], "code", "personal", "testlab-repo")
26
27
  # ]
27
28
  #
28
29
  # node :localhost do
@@ -39,8 +40,7 @@ require 'testlab/monkeys'
39
40
  # :cpus => 8,
40
41
  # :memory => 16384,
41
42
  # :box => 'raring64'
42
- # },
43
- # :repo => File.join(ENV['HOME'], "code", "personal", "testlab-repo")
43
+ # }
44
44
  # ]
45
45
  #
46
46
  # network :east do
@@ -103,6 +103,7 @@ class TestLab
103
103
  labfile = (options[:labfile] || 'Labfile')
104
104
  labfile_path = ZTK::Locator.find(labfile)
105
105
  @labfile = TestLab::Labfile.load(labfile_path)
106
+ @labfile.config.merge!(:testlab => self)
106
107
  end
107
108
 
108
109
  # Test Lab Nodes
@@ -202,6 +203,17 @@ class TestLab
202
203
  true
203
204
  end
204
205
 
206
+ # TestLab Configuration Directory
207
+ #
208
+ # Returns the path to the test lab configuration directory which is located
209
+ # off the repo directory under '.testlab'.
210
+ #
211
+ # @return [String] The path to the TestLab configuration directory.
212
+ def config_dir
213
+ directory = File.join(self.config[:repo], '.testlab')
214
+ File.expand_path(directory, File.dirname(__FILE__))
215
+ end
216
+
205
217
  # Provider Method Handler
206
218
  #
207
219
  # Proxies missing provider method calls to all nodes.
@@ -221,7 +233,7 @@ class TestLab
221
233
  #
222
234
  # These are special methods that we both include and extend on the parent
223
235
  # class.
224
- module ClassMethods
236
+ module DualMethods
225
237
 
226
238
  @@ui ||= nil
227
239
 
@@ -266,13 +278,13 @@ class TestLab
266
278
  #
267
279
  # @return [String] Constructed command line with arguments.
268
280
  def build_command_line(name, *args)
269
- executable = (ZTK::Locator.find('bin', name) rescue "/bin/env #{name}")
281
+ executable = (ZTK::Locator.find('bin', name) rescue "/usr/bin/env #{name}")
270
282
  [executable, args].flatten.compact.join(' ')
271
283
  end
272
284
 
273
285
  end
274
286
 
275
- include TestLab::ClassMethods
276
- extend TestLab::ClassMethods
287
+ include TestLab::DualMethods
288
+ extend TestLab::DualMethods
277
289
 
278
290
  end
@@ -147,6 +147,7 @@ describe TestLab::Container do
147
147
  subject.lxc.config.stub(:save) { true }
148
148
  subject.stub(:detect_arch) { "amd64" }
149
149
  subject.lxc.stub(:create) { true }
150
+ subject.node.ssh.stub(:exec)
150
151
  subject.create
151
152
  end
152
153
  end
@@ -163,6 +164,7 @@ describe TestLab::Container do
163
164
  subject.lxc.stub(:start) { true }
164
165
  subject.lxc.stub(:wait) { true }
165
166
  subject.lxc.stub(:state) { :running }
167
+ subject.lxc.stub(:attach)
166
168
  subject.up
167
169
  end
168
170
  end
data/spec/support/Labfile CHANGED
@@ -7,14 +7,16 @@ apt-get -y update
7
7
  apt-get -y install dnsutils
8
8
  EOF
9
9
 
10
+ REPO = File.dirname(__FILE__)
11
+
10
12
  config Hash[
11
- :domain => "default.zone"
13
+ :domain => "default.zone",
14
+ :repo => REPO
12
15
  ]
13
16
 
14
17
  node :localhost do
15
18
 
16
19
  components %w(resolv bind)
17
- route true
18
20
 
19
21
  provider TestLab::Provider::Vagrant
20
22
  config Hash[
@@ -24,14 +26,15 @@ node :localhost do
24
26
  :user => "vagrant",
25
27
  :port => 22,
26
28
  :cpus => 1,
27
- :memory => 512
28
- },
29
- :repo => File.dirname(__FILE__)
29
+ :memory => 512,
30
+ :file => REPO
31
+ }
30
32
  ]
31
33
 
32
34
  network :testnet do
33
35
  address '192.168.255.254/16'
34
36
  bridge :br0
37
+ route true
35
38
  end
36
39
 
37
40
  # DUAL NICs
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.4.0
4
+ version: 0.4.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-05-06 00:00:00.000000000 Z
12
+ date: 2013-05-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gli
@@ -281,7 +281,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
281
  version: '0'
282
282
  segments:
283
283
  - 0
284
- hash: 2598342112570301025
284
+ hash: 3337879606359400445
285
285
  required_rubygems_version: !ruby/object:Gem::Requirement
286
286
  none: false
287
287
  requirements:
@@ -290,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
290
290
  version: '0'
291
291
  segments:
292
292
  - 0
293
- hash: 2598342112570301025
293
+ hash: 3337879606359400445
294
294
  requirements: []
295
295
  rubyforge_project:
296
296
  rubygems_version: 1.8.25