testlab 0.4.16 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/tl +6 -1
- data/lib/testlab/container/actions.rb +16 -20
- data/lib/testlab/container/user.rb +32 -0
- data/lib/testlab/container.rb +3 -4
- data/lib/testlab/node/ssh.rb +4 -3
- data/lib/testlab/node/templates/node-setup.erb +11 -1
- data/lib/testlab/user/actions.rb +69 -0
- data/lib/testlab/user.rb +35 -0
- data/lib/testlab/version.rb +1 -1
- data/lib/testlab.rb +1 -0
- metadata +7 -4
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
|
-
#
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
85
|
-
|
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
|
data/lib/testlab/container.rb
CHANGED
@@ -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
|
data/lib/testlab/node/ssh.rb
CHANGED
@@ -30,9 +30,10 @@ class TestLab
|
|
30
30
|
c.proxy_keys = @provider.identity
|
31
31
|
|
32
32
|
c.host_name = container.ip
|
33
|
-
|
34
|
-
c.
|
35
|
-
c.
|
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
|
data/lib/testlab/user.rb
ADDED
@@ -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
|
data/lib/testlab/version.rb
CHANGED
data/lib/testlab.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.
|
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-
|
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: -
|
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: -
|
297
|
+
hash: -532232323948453701
|
295
298
|
requirements: []
|
296
299
|
rubyforge_project:
|
297
300
|
rubygems_version: 1.8.25
|