testlab 0.4.16 → 0.5.0

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
@@ -341,10 +341,14 @@ command :container do |c|
341
341
  c.desc 'Open an SSH console to a container'
342
342
  c.command :ssh do |ssh|
343
343
 
344
- ssh.desc 'Username'
344
+ ssh.desc 'Specify an SSH Username to use'
345
345
  ssh.arg_name 'username'
346
346
  ssh.flag [:u, :user]
347
347
 
348
+ ssh.desc 'Specify an SSH Identity Key to use'
349
+ ssh.arg_name 'key'
350
+ ssh.flag [:k, :key]
351
+
348
352
  ssh.action do |global_options, options, args|
349
353
  help_now!('id is required') if options[:id].nil?
350
354
 
@@ -353,6 +357,7 @@ command :container do |c|
353
357
 
354
358
  ssh_options = Hash.new
355
359
  ssh_options[:user] = options[:user]
360
+ ssh_options[:keys] = options[:key]
356
361
 
357
362
  container.ssh(ssh_options).console
358
363
  end
@@ -20,24 +20,18 @@ class TestLab
20
20
 
21
21
  self.lxc.create(*create_args)
22
22
 
23
- # TODO: This needs to really go somewhere else:
24
- home_dir = ((self.node.user == "root") ? %(/root) : %(/home/#{self.node.user}))
25
- container_home_dir = File.join(self.lxc.fs_root, "/home/ubuntu")
26
-
27
- home_authkeys = File.join(home_dir, ".ssh", "authorized_keys")
28
- container_authkeys = File.join(container_home_dir, ".ssh", "authorized_keys")
29
- container_authkeys2 = File.join(container_home_dir, ".ssh", "authorized_keys2")
30
-
31
- authkeys = {
32
- home_authkeys => container_authkeys,
33
- home_authkeys => container_authkeys2
34
- }
35
-
36
- self.node.ssh.exec(%(mkdir -pv #{File.join(container_home_dir, %(.ssh))}))
37
- authkeys.each do |source, destination|
38
- self.node.ssh.exec(%(sudo cp -v #{source} #{destination}))
39
- self.node.ssh.exec(%(sudo chown -v 1000:1000 #{destination}))
40
- self.node.ssh.exec(%(sudo chmod -v 644 #{destination}))
23
+ # Ensure the container APT calls use apt-cacher-ng on the node
24
+ gateway_ip = self.primary_interface.network.ip
25
+ apt_conf_d_proxy_file = File.join(self.lxc.fs_root, "etc", "apt", "apt.conf.d", "02proxy")
26
+ self.node.ssh.exec(%(sudo mkdir -pv #{File.dirname(apt_conf_d_proxy_file)}))
27
+ self.node.ssh.exec(%(echo 'Acquire::http { Proxy "http://#{gateway_ip}:3142"; };' | sudo tee #{apt_conf_d_proxy_file}))
28
+
29
+ # Fix the APT sources since LXC mudges them when using apt-cacher-ng
30
+ apt_conf_sources_file = File.join(self.lxc.fs_root, "etc", "apt", "sources.list")
31
+ self.node.ssh.exec(%(sudo sed -i 's/127.0.0.1:3142\\///g' #{apt_conf_sources_file}))
32
+
33
+ self.users.each do |u|
34
+ u.create
41
35
  end
42
36
 
43
37
  end
@@ -81,8 +75,10 @@ class TestLab
81
75
 
82
76
  (self.lxc.state != :running) and raise ContainerError, "The container failed to online!"
83
77
 
84
- # TODO: This needs to really go somewhere else:
85
- 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'))
78
+ self.users.each do |u|
79
+ u.up
80
+ end
81
+
86
82
  end
87
83
 
88
84
  true
@@ -0,0 +1,32 @@
1
+ class TestLab
2
+ class Container
3
+
4
+ module User
5
+
6
+ # Container primary user
7
+ #
8
+ # Returns the primary user for the container. If the container has
9
+ # multiple users, this is based on which ever user is marked
10
+ # with the primary flag. If the container only has one user, then
11
+ # it is returned.
12
+ #
13
+ # @return [TestLab::User] The primary user for the container.
14
+ def primary_user
15
+ if self.users.count == 0
16
+ case self.distro.downcase
17
+ when 'ubuntu' then
18
+ TestLab::User.new "ubuntu" do
19
+ password 'ubuntu'
20
+ end
21
+ end
22
+ elsif self.users.any?{ |u| u.primary == true }
23
+ self.users.find{ |u| u.primary == true }
24
+ else
25
+ self.users.first
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -70,6 +70,7 @@ class TestLab
70
70
  autoload :MethodMissing, 'testlab/container/method_missing'
71
71
  autoload :SSH, 'testlab/container/ssh'
72
72
  autoload :Status, 'testlab/container/status'
73
+ autoload :User, 'testlab/container/user'
73
74
 
74
75
  include TestLab::Container::Actions
75
76
  include TestLab::Container::Generators
@@ -79,6 +80,7 @@ class TestLab
79
80
  include TestLab::Container::MethodMissing
80
81
  include TestLab::Container::SSH
81
82
  include TestLab::Container::Status
83
+ include TestLab::Container::User
82
84
 
83
85
  extend TestLab::Container::ClassMethods
84
86
 
@@ -87,16 +89,13 @@ class TestLab
87
89
  # Associations and Attributes
88
90
  belongs_to :node, :class_name => 'TestLab::Node'
89
91
  has_many :interfaces, :class_name => 'TestLab::Interface'
92
+ has_many :users, :class_name => 'TestLab::User'
90
93
 
91
94
  attribute :provisioner
92
95
  attribute :config, :default => Hash.new
93
96
 
94
97
  attribute :domain
95
98
 
96
- attribute :user, :default => 'ubuntu'
97
- attribute :passwd, :default => 'ubuntu'
98
- attribute :keys
99
-
100
99
  attribute :distro, :default => 'ubuntu'
101
100
  attribute :release, :default => 'precise'
102
101
  attribute :arch
@@ -30,9 +30,10 @@ class TestLab
30
30
  c.proxy_keys = @provider.identity
31
31
 
32
32
  c.host_name = container.ip
33
- c.user = (options[:user] || container.user)
34
- c.password = (options[:passwd] || container.passwd)
35
- c.keys = (options[:keys] || container.keys || @provider.identity)
33
+
34
+ c.user = (options[:user] || container.primary_user.id)
35
+ c.password = (options[:passwd] || container.primary_user.password)
36
+ c.keys = (options[:keys] || container.primary_user.keys || @provider.identity)
36
37
  end
37
38
  end
38
39
  @container_ssh[name]
@@ -2,11 +2,21 @@ set -x
2
2
 
3
3
  # Update APT and ensure our required packages are installed
4
4
  apt-get -y update
5
- apt-get -y install lxc bridge-utils debootstrap yum iptables ntpdate ntp
5
+ apt-get -y install lxc bridge-utils debootstrap yum iptables ntpdate ntp apt-cacher-ng
6
+
7
+ # Ensure APT Cache-NG is running
8
+ service apt-cacher-ng restart || service apt-cacher-ng start
9
+ cat <<EOF | tee /etc/apt/apt.conf.d/02proxy
10
+ Acquire::http { Proxy "http://127.0.0.1:3142"; };
11
+ EOF
6
12
 
7
13
  # Ensure the default lxc networking services are off
8
14
  service lxc-net stop
9
15
 
16
+ # Ensure that we use APT Cacher-NG for building containers
17
+ grep "^MIRROR" /etc/default/lxc || echo "MIRROR=\"http://127.0.0.1:3142/archive.ubuntu.com/ubuntu\"" | tee -a /etc/default/lxc
18
+ service lxc restart || service lxc start
19
+
10
20
  # Ensure NTP services are enabled and running
11
21
  service ntp restart || service ntp start
12
22
 
@@ -0,0 +1,69 @@
1
+ class TestLab
2
+ class User
3
+
4
+ module Actions
5
+
6
+ # Create the user
7
+ #
8
+ # @return [Boolean] True if successful.
9
+ def create
10
+ @ui.logger.debug { "User Create: #{self.id} " }
11
+
12
+ node_home_dir = ((self.container.node.user == "root") ? %(/root) : %(/home/#{self.container.node.user}))
13
+ node_authkeys = File.join(node_home_dir, ".ssh", "authorized_keys")
14
+
15
+ user_home_dir = File.join(self.container.lxc.fs_root, ((self.id == "root") ? %(/root) : %(/home/#{self.id})))
16
+ user_authkeys = File.join(user_home_dir, ".ssh", "authorized_keys")
17
+ user_authkeys2 = File.join(user_home_dir, ".ssh", "authorized_keys2")
18
+
19
+ # ensure the container user exists
20
+ container_passwd_file = File.join(self.container.lxc.fs_root, "etc", "passwd")
21
+ if self.container.node.ssh.exec(%(sudo grep "#{self.id}" #{container_passwd_file}), :ignore_exit_status => true).exit_code != 0
22
+
23
+ if !self.gid.nil?
24
+ groupadd_command = %(groupadd --gid #{self.gid} #{self.id})
25
+ self.container.node.ssh.exec(%(sudo chroot #{self.container.lxc.fs_root} /bin/bash -c '#{groupadd_command}'))
26
+ end
27
+
28
+ useradd_command = %W(useradd --create-home --shell /bin/bash --groups sudo --password #{self.password})
29
+ useradd_command << "--uid #{self.uid}" if !self.uid.nil?
30
+ useradd_command << "--gid #{self.gid}" if !self.gid.nil?
31
+ useradd_command << self.id
32
+ useradd_command = useradd_command.flatten.compact.join(' ')
33
+
34
+ self.container.node.ssh.exec(%(sudo chroot #{self.container.lxc.fs_root} /bin/bash -c '#{useradd_command}'))
35
+ end
36
+
37
+ # ensure the user user gets our node user key
38
+ authkeys = {
39
+ node_authkeys => user_authkeys,
40
+ node_authkeys => user_authkeys2
41
+ }
42
+
43
+ authkeys.each do |source, destination|
44
+ self.container.node.ssh.exec(%(sudo mkdir -pv #{File.dirname(destination)}))
45
+ self.container.node.ssh.exec(%(sudo cp -v #{source} #{destination}))
46
+ self.container.node.ssh.exec(%(sudo chmod -v 644 #{destination}))
47
+ end
48
+
49
+ true
50
+ end
51
+
52
+ # Up the user
53
+ #
54
+ # @return [Boolean] True if successful.
55
+ def up
56
+ @ui.logger.debug { "User Up: #{self.id}" }
57
+
58
+ # ensure the container user home directory is owned by them
59
+ home_dir = self.container.lxc.attach(%(-- /bin/bash -c 'grep #{self.id} /etc/passwd | cut -d ":" -f6')).strip
60
+ self.container.lxc.attach(%(-- /bin/bash -c 'sudo chown -Rv $(id -u #{self.id}):$(id -g #{self.id}) #{home_dir}'))
61
+
62
+ # ensure the sudo user group can do passwordless sudo
63
+ self.container.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
+ end
65
+
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,35 @@
1
+ class TestLab
2
+
3
+ # User Error Class
4
+ class UserError < TestLabError; end
5
+
6
+ # User Class
7
+ #
8
+ # @author Zachary Patten <zachary AT jovelabs DOT com>
9
+ class User < ZTK::DSL::Base
10
+
11
+ # Sub-Modules
12
+ autoload :Actions, 'testlab/user/actions'
13
+
14
+ include TestLab::User::Actions
15
+
16
+ # Associations and Attributes
17
+ belongs_to :container, :class_name => 'TestLab::Container'
18
+
19
+ attribute :user
20
+ attribute :password
21
+ attribute :keys
22
+ attribute :uid
23
+ attribute :gid
24
+
25
+ attribute :primary, :default => false
26
+
27
+ def initialize(*args)
28
+ super(*args)
29
+
30
+ @ui = TestLab.ui
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -1,6 +1,6 @@
1
1
  class TestLab
2
2
  unless const_defined?(:VERSION)
3
3
  # TestLab Gem Version
4
- VERSION = "0.4.16"
4
+ VERSION = "0.5.0"
5
5
  end
6
6
  end
data/lib/testlab.rb CHANGED
@@ -93,6 +93,7 @@ class TestLab
93
93
  autoload :Node, 'testlab/node'
94
94
  autoload :Provider, 'testlab/provider'
95
95
  autoload :Provisioner, 'testlab/provisioner'
96
+ autoload :User, 'testlab/user'
96
97
  autoload :Utility, 'testlab/utility'
97
98
 
98
99
  include TestLab::Utility::Misc
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.16
4
+ version: 0.5.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-06-05 00:00:00.000000000 Z
12
+ date: 2013-06-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gli
@@ -217,6 +217,7 @@ files:
217
217
  - lib/testlab/container/method_missing.rb
218
218
  - lib/testlab/container/ssh.rb
219
219
  - lib/testlab/container/status.rb
220
+ - lib/testlab/container/user.rb
220
221
  - lib/testlab/interface.rb
221
222
  - lib/testlab/labfile.rb
222
223
  - lib/testlab/monkeys.rb
@@ -252,6 +253,8 @@ files:
252
253
  - lib/testlab/provisioners/shell.rb
253
254
  - lib/testlab/provisioners/templates/chef/omnibus.erb
254
255
  - lib/testlab/provisioners/templates/chef/omnitruck.erb
256
+ - lib/testlab/user.rb
257
+ - lib/testlab/user/actions.rb
255
258
  - lib/testlab/utility.rb
256
259
  - lib/testlab/utility/cidr.rb
257
260
  - lib/testlab/utility/misc.rb
@@ -282,7 +285,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
282
285
  version: '0'
283
286
  segments:
284
287
  - 0
285
- hash: -1044264548674071638
288
+ hash: -532232323948453701
286
289
  required_rubygems_version: !ruby/object:Gem::Requirement
287
290
  none: false
288
291
  requirements:
@@ -291,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
294
  version: '0'
292
295
  segments:
293
296
  - 0
294
- hash: -1044264548674071638
297
+ hash: -532232323948453701
295
298
  requirements: []
296
299
  rubyforge_project:
297
300
  rubygems_version: 1.8.25