gepetto 0.0.8
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/History.txt +4 -0
- data/Manifest.txt +35 -0
- data/README.rdoc +212 -0
- data/Rakefile +28 -0
- data/app_generators/gepetto/USAGE +0 -0
- data/app_generators/gepetto/gepetto_generator.rb +35 -0
- data/app_generators/gepetto/templates/Rakefile +24 -0
- data/app_generators/gepetto/templates/config/fileserver.conf +7 -0
- data/app_generators/gepetto/templates/config/puppet.conf +11 -0
- data/app_generators/gepetto/templates/manifests/classes/empty.pp +1 -0
- data/app_generators/gepetto/templates/manifests/defaults.pp +12 -0
- data/app_generators/gepetto/templates/manifests/nodes.pp +5 -0
- data/app_generators/gepetto/templates/manifests/site.pp +9 -0
- data/app_generators/gepetto/templates/manifests/templates.pp +0 -0
- data/app_generators/gepetto/templates/script/module +67 -0
- data/app_generators/gepetto/templates/script/puppetca +3 -0
- data/app_generators/gepetto/templates/script/puppetmasterd +13 -0
- data/app_generators/gepetto/templates/script/puppetrun +2 -0
- data/bin/gepetto +18 -0
- data/gepetto.gemspec +37 -0
- data/lib/gepetto.rb +6 -0
- data/lib/gepetto/tasks.rb +1 -0
- data/puppet_generators/module/USAGE +18 -0
- data/puppet_generators/module/module_generator.rb +24 -0
- data/puppet_generators/module/templates/README +0 -0
- data/puppet_generators/module/templates/manifests/init.pp +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/tasks/host.pp +75 -0
- data/tasks/log.rake +9 -0
- data/tasks/puppet.rake +8 -0
- data/tasks/sandbox.pp +101 -0
- data/tasks/sandbox.rake +437 -0
- data/tasks/tmp.rake +24 -0
- data/tasks/utils.rake +17 -0
- metadata +104 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
# create tmp if needed, other directories are created by puppetmasterd
|
4
|
+
[ -d tmp ] || mkdir tmp
|
5
|
+
|
6
|
+
# change working directories
|
7
|
+
OPTIONS="--logdir=$PWD/log --vardir=$PWD/tmp/lib --rundir=$PWD/tmp/run --ssldir=$PWD/tmp/ssl"
|
8
|
+
# use local files
|
9
|
+
OPTIONS="$OPTIONS --templatedir=$PWD/templates --manifestdir=$PWD/manifests --modulepath=$PWD/modules --confdir=$PWD/config"
|
10
|
+
|
11
|
+
OPTIONS="$OPTIONS --certname=puppet --logdest=console"
|
12
|
+
|
13
|
+
/usr/sbin/puppetmasterd --no-daemonize $OPTIONS $*
|
data/bin/gepetto
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rubigen'
|
5
|
+
|
6
|
+
if %w(-v --version).include? ARGV.first
|
7
|
+
require 'gepetto/version'
|
8
|
+
puts "#{File.basename($0)} #{Gepetto::VERSION}"
|
9
|
+
exit(0)
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubigen/scripts/generate'
|
13
|
+
RubiGen::Base.use_application_sources!
|
14
|
+
|
15
|
+
RubiGen::Base.prepend_sources(
|
16
|
+
RubiGen::PathSource.new(:app, File.join(File.dirname(__FILE__), "..", "app_generators"))
|
17
|
+
)
|
18
|
+
RubiGen::Scripts::Generate.new.run(ARGV, :generator => 'gepetto')
|
data/gepetto.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{gepetto}
|
5
|
+
s.version = "0.0.7"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Alban Peignier"]
|
9
|
+
s.date = %q{2009-08-20}
|
10
|
+
s.default_executable = %q{gepetto}
|
11
|
+
s.description = %q{A helper suite for Puppet projects to create, manage and help daily development
|
12
|
+
|
13
|
+
More information about Puppet: http://reductivelabs.com/trac/puppet/}
|
14
|
+
s.email = ["alban.peignier@free.fr"]
|
15
|
+
s.executables = ["gepetto"]
|
16
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
|
17
|
+
s.files = ["History.txt", "Manifest.txt", "README.rdoc", "Rakefile", "app_generators/gepetto/USAGE", "app_generators/gepetto/gepetto_generator.rb", "app_generators/gepetto/templates/Rakefile", "app_generators/gepetto/templates/config/fileserver.conf", "app_generators/gepetto/templates/config/puppet.conf", "app_generators/gepetto/templates/manifests/classes/empty.pp", "app_generators/gepetto/templates/manifests/defaults.pp", "app_generators/gepetto/templates/manifests/nodes.pp", "app_generators/gepetto/templates/manifests/site.pp", "app_generators/gepetto/templates/manifests/templates.pp", "app_generators/gepetto/templates/script/module", "app_generators/gepetto/templates/script/puppetca", "app_generators/gepetto/templates/script/puppetmasterd", "app_generators/gepetto/templates/script/puppetrun", "bin/gepetto", "gepetto.gemspec", "lib/gepetto.rb", "lib/gepetto/tasks.rb", "puppet_generators/module/USAGE", "puppet_generators/module/module_generator.rb", "puppet_generators/module/templates/README", "puppet_generators/module/templates/manifests/init.pp", "script/destroy", "script/generate", "tasks/host.pp", "tasks/log.rake", "tasks/puppet.rake", "tasks/sandbox.pp", "tasks/sandbox.rake", "tasks/tmp.rake", "tasks/utils.rake"]
|
18
|
+
s.homepage = %q{http://github.com/albanpeignier/gepetto/}
|
19
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
s.rubyforge_project = %q{gepetto}
|
22
|
+
s.rubygems_version = %q{1.3.4}
|
23
|
+
s.summary = %q{A helper suite for Puppet projects to create, manage and help daily development More information about Puppet: http://reductivelabs.com/trac/puppet/}
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
27
|
+
s.specification_version = 3
|
28
|
+
|
29
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
30
|
+
s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<hoe>, [">= 2.3.3"])
|
33
|
+
end
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<hoe>, [">= 2.3.3"])
|
36
|
+
end
|
37
|
+
end
|
data/lib/gepetto.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.join(File.dirname(__FILE__), %w[.. .. tasks], '**/*.rake')].each { |rake| load rake }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Description:
|
2
|
+
Create an empty module organisation as specified by
|
3
|
+
http://reductivelabs.com/trac/puppet/wiki/ModuleOrganisation
|
4
|
+
|
5
|
+
This generates a module directories and files into modules/<modulename>.
|
6
|
+
|
7
|
+
Example:
|
8
|
+
./script/generate module passenger
|
9
|
+
|
10
|
+
creates directories :
|
11
|
+
modules/passenger/templates
|
12
|
+
modules/passenger/files
|
13
|
+
modules/passenger/depends
|
14
|
+
|
15
|
+
creates files :
|
16
|
+
modules/passenger/README
|
17
|
+
modules/passenger/manifests/init.pp
|
18
|
+
modules/passenger/manifests/defaults.pp
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
class ModuleGenerator < RubiGen::Base
|
4
|
+
|
5
|
+
attr_reader :module_name
|
6
|
+
|
7
|
+
def initialize(runtime_args, runtime_options = {})
|
8
|
+
super
|
9
|
+
usage if args.empty?
|
10
|
+
@module_name = args.shift
|
11
|
+
@destination_root = "modules/#{module_name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def manifest
|
15
|
+
record do |m|
|
16
|
+
# Root directory and all subdirectories.
|
17
|
+
m.directory ''
|
18
|
+
%w{manifests files templates}.each { |path| m.directory path }
|
19
|
+
m.template_copy_each %w( README )
|
20
|
+
m.template_copy_each %w( init.pp ), 'manifests'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
File without changes
|
File without changes
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/tasks/host.pp
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
Exec { path => "/usr/bin:/usr/sbin/:/bin:/sbin" }
|
2
|
+
|
3
|
+
# install qemu
|
4
|
+
|
5
|
+
package { qemu:
|
6
|
+
ensure => "latest"
|
7
|
+
}
|
8
|
+
|
9
|
+
# compile kqemu module
|
10
|
+
|
11
|
+
package { kqemu-source:
|
12
|
+
ensure => "latest",
|
13
|
+
require => Package[qemu]
|
14
|
+
}
|
15
|
+
|
16
|
+
exec { "modass-kqemu":
|
17
|
+
# modass returns 249 with non-inter ...
|
18
|
+
command => 'module-assistant --non-inter a-i kqemu || dpkg -l "kqemu-modules-`uname -r`" | grep ^ii',
|
19
|
+
unless => 'dpkg -l "kqemu-modules-`uname -r`" | grep ^ii',
|
20
|
+
require => Package[kqemu-source]
|
21
|
+
}
|
22
|
+
|
23
|
+
exec { "add kqemu in /etc/modules":
|
24
|
+
command => "echo kqemu >> /etc/modules",
|
25
|
+
unless => "grep kqemu /etc/modules",
|
26
|
+
require => Exec["modass-kqemu"]
|
27
|
+
}
|
28
|
+
|
29
|
+
exec { "modprobe-kqemu":
|
30
|
+
command => "modprobe kqemu",
|
31
|
+
unless => "lsmod | grep kqemu",
|
32
|
+
require => Exec["modass-kqemu"]
|
33
|
+
}
|
34
|
+
|
35
|
+
file { "/dev/kqemu":
|
36
|
+
# default permissions on debian, but not on ubuntu
|
37
|
+
mode => 666,
|
38
|
+
require => Exec["modprobe-kqemu"]
|
39
|
+
}
|
40
|
+
|
41
|
+
# install uml-utilities for tunctl
|
42
|
+
|
43
|
+
package { uml-utilities: }
|
44
|
+
|
45
|
+
exec { "add tun in /etc/modules":
|
46
|
+
command => "echo tun >> /etc/modules",
|
47
|
+
unless => "grep tun /etc/modules"
|
48
|
+
}
|
49
|
+
|
50
|
+
exec { "modprobe tun":
|
51
|
+
unless => "lsmod | grep tun"
|
52
|
+
}
|
53
|
+
|
54
|
+
file { "/dev/net/tun":
|
55
|
+
mode => 666
|
56
|
+
}
|
57
|
+
|
58
|
+
# provide a basic qemu-ifup
|
59
|
+
|
60
|
+
file { "/etc/qemu-ifup":
|
61
|
+
mode => 755,
|
62
|
+
content => '#!/bin/sh -x
|
63
|
+
|
64
|
+
if [ "$USER" != "root" -o "$1" != "sudo" ]; then
|
65
|
+
exec sudo -p "Password for $0:" $0 sudo $1
|
66
|
+
fi
|
67
|
+
|
68
|
+
[ "$1" = "sudo" ] && shift
|
69
|
+
|
70
|
+
/sbin/ifconfig $1 172.20.0.1
|
71
|
+
iptables -t nat -A POSTROUTING -s 172.20.0.1/24 -o eth0 -j MASQUERADE
|
72
|
+
sysctl -w net.ipv4.ip_forward=1
|
73
|
+
',
|
74
|
+
require => Package[qemu]
|
75
|
+
}
|
data/tasks/log.rake
ADDED
data/tasks/puppet.rake
ADDED
data/tasks/sandbox.pp
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Minimal settings to boot sandbox image with qemu
|
2
|
+
|
3
|
+
# These variables are defined by rake task
|
4
|
+
#$host_ip='172.20.0.1'
|
5
|
+
#$sandbox_ip='172.20.0.2'
|
6
|
+
|
7
|
+
Exec { path => "/usr/bin:/usr/sbin/:/bin:/sbin" }
|
8
|
+
|
9
|
+
file { "/etc/fstab":
|
10
|
+
content => "/dev/hda1 / ext3 errors=remount-ro 0 1
|
11
|
+
proc /proc proc defaults 0 0
|
12
|
+
"
|
13
|
+
}
|
14
|
+
|
15
|
+
# Console on ttyS0 not tty1
|
16
|
+
exec { "inittab-ttyS0-getty":
|
17
|
+
command => "sed -i '/getty 38400 tty1/ s/tty1/ttyS0/' /etc/inittab",
|
18
|
+
unless => "grep 'getty 38400 ttyS0' /etc/inittab"
|
19
|
+
}
|
20
|
+
|
21
|
+
# and no other gettys
|
22
|
+
exec { "inittab-no-tty-gettys":
|
23
|
+
command => "sed -i '/getty 38400 tty[23456]/ d' /etc/inittab",
|
24
|
+
onlyif => "grep 'getty 38400 tty[23456]' /etc/inittab"
|
25
|
+
}
|
26
|
+
|
27
|
+
file { "/etc/hostname":
|
28
|
+
content => "sandbox"
|
29
|
+
}
|
30
|
+
|
31
|
+
# an host object doesn't find a provider
|
32
|
+
file { "/etc/hosts":
|
33
|
+
content => "127.0.0.1 localhost
|
34
|
+
127.0.1.1 sandbox
|
35
|
+
$host_ip puppet
|
36
|
+
"
|
37
|
+
}
|
38
|
+
|
39
|
+
# root's password is 'root'
|
40
|
+
user { root:
|
41
|
+
password => '$1$aybpiIGf$cB7iFDNZvViQtQjEZ5HFQ0'
|
42
|
+
}
|
43
|
+
|
44
|
+
package { [console-common,console-tools,console-data,base-config,man-db,manpages]:
|
45
|
+
ensure => absent
|
46
|
+
}
|
47
|
+
|
48
|
+
# if network configuration changes, eth0 is renamed by udev :-/
|
49
|
+
file { "/etc/udev/rules.d/70-persistent-net.rules":
|
50
|
+
ensure => absent
|
51
|
+
}
|
52
|
+
|
53
|
+
file { "/etc/network/interfaces":
|
54
|
+
content => "auto lo
|
55
|
+
iface lo inet loopback
|
56
|
+
|
57
|
+
auto eth0
|
58
|
+
iface eth0 inet static
|
59
|
+
address $sandbox_ip
|
60
|
+
netmask 255.255.255.0
|
61
|
+
gateway $host_ip
|
62
|
+
dns-nameservers $host_ip
|
63
|
+
"
|
64
|
+
}
|
65
|
+
|
66
|
+
# puppet configuration
|
67
|
+
|
68
|
+
file { "/etc/default/puppet":
|
69
|
+
content => 'START=no
|
70
|
+
DAEMON_OPTS="-w 5"
|
71
|
+
'
|
72
|
+
}
|
73
|
+
|
74
|
+
file { "/etc/puppet/namespaceauth.conf":
|
75
|
+
content => "[puppetrunner]
|
76
|
+
allow $host_ip
|
77
|
+
"
|
78
|
+
}
|
79
|
+
|
80
|
+
file { "/etc/puppet/puppet.conf":
|
81
|
+
content => '[main]
|
82
|
+
logdir=/var/log/puppet
|
83
|
+
vardir=/var/lib/puppet
|
84
|
+
ssldir=/var/lib/puppet/ssl
|
85
|
+
rundir=/var/run/puppet
|
86
|
+
factpath=$vardir/lib/facter
|
87
|
+
pluginsync=false
|
88
|
+
color=false
|
89
|
+
|
90
|
+
[puppetd]
|
91
|
+
report=true
|
92
|
+
# run puppetd .. every day
|
93
|
+
runinterval = 86400
|
94
|
+
listen=true
|
95
|
+
'
|
96
|
+
}
|
97
|
+
|
98
|
+
exec { "syslog-to-ttyS0":
|
99
|
+
command => "echo '*.* -/dev/ttyS0' >> /etc/rsyslog.conf",
|
100
|
+
unless => 'grep /dev/ttyS0 /etc/rsyslog.conf'
|
101
|
+
}
|
data/tasks/sandbox.rake
ADDED
@@ -0,0 +1,437 @@
|
|
1
|
+
require 'rake/tasklib'
|
2
|
+
require 'ping'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
class Sandbox < Rake::TaskLib
|
6
|
+
|
7
|
+
def self.default_architecture
|
8
|
+
case PLATFORM
|
9
|
+
when /x86_64/
|
10
|
+
"amd64"
|
11
|
+
else
|
12
|
+
"i386"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
@@images_directory = "/var/tmp"
|
17
|
+
|
18
|
+
def self.images_directory
|
19
|
+
@@images_directory
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.images_directory=(directory)
|
23
|
+
@@images_directory = directory
|
24
|
+
end
|
25
|
+
|
26
|
+
def puppet_file(name)
|
27
|
+
File.dirname(__FILE__) + "/#{name}.pp"
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :name
|
31
|
+
attr_accessor :bootstraper, :ip_address, :host_ip_address, :tap_device
|
32
|
+
attr_accessor :disk_size, :memory_size, :mount_point
|
33
|
+
attr_accessor :architecture
|
34
|
+
|
35
|
+
def initialize(name = "sandbox")
|
36
|
+
@name = name
|
37
|
+
|
38
|
+
init
|
39
|
+
yield self if block_given?
|
40
|
+
define
|
41
|
+
end
|
42
|
+
|
43
|
+
def define
|
44
|
+
@architecture = Sandbox.default_architecture
|
45
|
+
bootstraper = DebianBoostraper.new
|
46
|
+
|
47
|
+
@ip_address ||= '172.20.0.2'
|
48
|
+
@host_ip_address ||= @ip_address.gsub(/\.[0-9]+$/,'.1')
|
49
|
+
|
50
|
+
@disk_size ||= '512M'
|
51
|
+
@memory_size ||= '128M'
|
52
|
+
|
53
|
+
@mount_point ||= "/mnt/#{name}"
|
54
|
+
@tap_device ||= 'tap0'
|
55
|
+
end
|
56
|
+
|
57
|
+
def bootstraper=(bootstraper)
|
58
|
+
@bootstraper = bootstraper
|
59
|
+
sync_architecture
|
60
|
+
end
|
61
|
+
|
62
|
+
def architecture=(architecture)
|
63
|
+
@architecture = architecture
|
64
|
+
sync_architecture
|
65
|
+
end
|
66
|
+
|
67
|
+
def sync_architecture
|
68
|
+
if self.bootstraper and self.architecture
|
69
|
+
self.bootstraper.architecture = self.architecture
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def kernel_architecture
|
74
|
+
case self.architecture
|
75
|
+
when 'i386'
|
76
|
+
'686'
|
77
|
+
else
|
78
|
+
self.architecture
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def init
|
83
|
+
namespace @name do
|
84
|
+
|
85
|
+
desc "Setup local machine to host sandbox"
|
86
|
+
task :setup => 'tmp:create' do
|
87
|
+
sudo "puppet #{puppet_file(:host)}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Mix between these ways :
|
91
|
+
# - http://www.mail-archive.com/qemu-devel@nongnu.org/msg01208.html
|
92
|
+
# - http://www.geocities.com/gtalon51/Articles/Minimal_Linux_system/Minimal_Linux_system.html
|
93
|
+
# - qemu-make-debian-root
|
94
|
+
namespace :create do
|
95
|
+
task :image do
|
96
|
+
sh "qemu-img create -f raw #{disk_image} #{disk_size}"
|
97
|
+
# create the partition table
|
98
|
+
sh "echo '63,' | /sbin/sfdisk --no-reread -uS -H16 -S63 #{disk_image}"
|
99
|
+
end
|
100
|
+
|
101
|
+
task :fs do
|
102
|
+
# format the filesystem
|
103
|
+
begin
|
104
|
+
sudo "losetup -o #{fs_offset} /dev/loop0 #{disk_image}"
|
105
|
+
|
106
|
+
# because '/sbin/sfdisk -s /dev/loop0' returns a wrong value :
|
107
|
+
extract_fs_block_size = "/sbin/sfdisk -l #{disk_image} 2> /dev/null | awk '/img1/ { gsub(\"\\+\", \"\", $5); print $5 }'"
|
108
|
+
|
109
|
+
sudo "/sbin/mke2fs -jqF /dev/loop0 `#{extract_fs_block_size}`"
|
110
|
+
ensure
|
111
|
+
sudo "losetup -d /dev/loop0"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
task :system do
|
116
|
+
# install a debian base system
|
117
|
+
mount do
|
118
|
+
bootstraper.bootstrap mount_point
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
task :kernel do
|
123
|
+
mount do
|
124
|
+
chroot_sh "echo 'do_initrd = Yes' >> /etc/kernel-img.conf"
|
125
|
+
|
126
|
+
kernel_package =
|
127
|
+
case self.bootstraper.version
|
128
|
+
when 'etch', 'lenny'
|
129
|
+
"linux-image-2.6-#{kernel_architecture}"
|
130
|
+
when 'hardy'
|
131
|
+
'linux-image-2.6.24-16-generic'
|
132
|
+
when 'intrepid'
|
133
|
+
'linux-image-generic'
|
134
|
+
end
|
135
|
+
|
136
|
+
chroot_sh "DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes #{kernel_package}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
task :grub do
|
141
|
+
mount do
|
142
|
+
chroot_sh "DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes grub"
|
143
|
+
|
144
|
+
grub_dir = "#{mount_point}/boot/grub"
|
145
|
+
chroot_sh "mkdir /boot/grub" unless File.exists?(grub_dir)
|
146
|
+
|
147
|
+
stage_files = Dir["#{mount_point}/usr/lib/grub/**/stage?", "#{mount_point}/usr/lib/grub/**/e2fs_stage1_5"]
|
148
|
+
sudo "cp #{stage_files.join(' ')} #{grub_dir}"
|
149
|
+
|
150
|
+
Tempfile.open('menu_lst') do |f|
|
151
|
+
f.write(['default 0',
|
152
|
+
'timeout 0',
|
153
|
+
'title Linux',
|
154
|
+
'root (hd0,0)',
|
155
|
+
'kernel /vmlinuz root=/dev/hda1 ro',
|
156
|
+
'initrd /initrd.img'].join("\n"))
|
157
|
+
f.close
|
158
|
+
sudo "cp #{f.path} #{grub_dir}/menu.lst"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
Tempfile.open('grub_input') do |f|
|
163
|
+
f.write(["device (hd0) #{disk_image}",
|
164
|
+
"root (hd0,0)",
|
165
|
+
"setup (hd0)",
|
166
|
+
"quit"].join("\n"))
|
167
|
+
f.close
|
168
|
+
sudo "grub --device-map=/dev/null < #{f.path}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
task :config do
|
173
|
+
Tempfile.open('sandbox_puppet_file') do |sandbox_puppet_file|
|
174
|
+
sandbox_puppet_file.puts "$host_ip='#{host_ip_address}'"
|
175
|
+
sandbox_puppet_file.puts "$sandbox_ip='#{ip_address}'"
|
176
|
+
sandbox_puppet_file.puts IO.read(puppet_file(:sandbox))
|
177
|
+
|
178
|
+
sandbox_puppet_file.close
|
179
|
+
|
180
|
+
# finalize configuration with puppet
|
181
|
+
mount do
|
182
|
+
sudo "cp #{sandbox_puppet_file.path} #{mount_point}/etc/sandbox.pp"
|
183
|
+
sudo "chroot #{mount_point} puppet /etc/sandbox.pp"
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
task :tap_device do
|
189
|
+
unless tap_device_exists?
|
190
|
+
sudo "tunctl -u #{ENV['USER']} -t #{tap_device}"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
task :snapshot do
|
195
|
+
snapshot(:initial)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
desc "Create a fresh image for sandbox"
|
200
|
+
task :create => [ 'clean', 'create:image', 'create:fs', 'create:system', 'create:kernel', 'create:grub', 'create:config', 'create:snapshot' ]
|
201
|
+
|
202
|
+
desc "Destroy sandbox images"
|
203
|
+
task :destroy => 'clean' do
|
204
|
+
rm_f disk_image
|
205
|
+
rm_f disk_image(:initial)
|
206
|
+
end
|
207
|
+
|
208
|
+
desc "Start sandbox"
|
209
|
+
task :start => ['create:tap_device', 'tmp:create'] do
|
210
|
+
start
|
211
|
+
end
|
212
|
+
|
213
|
+
desc "Start sandbox from initial image in snapshot"
|
214
|
+
task :start_from_initial do
|
215
|
+
start :hda => disk_image(:initial), :snapshot => true
|
216
|
+
end
|
217
|
+
|
218
|
+
task :wait do
|
219
|
+
wait
|
220
|
+
end
|
221
|
+
|
222
|
+
desc "Stop sandbox"
|
223
|
+
task :stop do
|
224
|
+
sh "kill -9 `cat tmp/run/#{name}.pid`"
|
225
|
+
end
|
226
|
+
|
227
|
+
task :revert do
|
228
|
+
sh "qemu-img convert -O raw #{disk_image(:initial)} #{disk_image}"
|
229
|
+
end
|
230
|
+
|
231
|
+
task :mount do
|
232
|
+
mount_image
|
233
|
+
end
|
234
|
+
|
235
|
+
task :umount do
|
236
|
+
umount_image
|
237
|
+
end
|
238
|
+
|
239
|
+
task :clean => 'puppet:clean' do
|
240
|
+
# clean known_hosts
|
241
|
+
known_hosts_file="#{ENV['HOME']}/.ssh/known_hosts"
|
242
|
+
sh "sed -i '/#{hostname},#{ip_address}/ d' #{known_hosts_file}" if File.exists?(known_hosts_file)
|
243
|
+
end
|
244
|
+
|
245
|
+
task :status do
|
246
|
+
status
|
247
|
+
end
|
248
|
+
|
249
|
+
namespace :puppet do
|
250
|
+
|
251
|
+
desc "Run puppetd in sandbox"
|
252
|
+
task :run do
|
253
|
+
sh "./script/puppetrun --host #{hostname}"
|
254
|
+
end
|
255
|
+
|
256
|
+
desc "Sign a request from sandbox"
|
257
|
+
task :sign do
|
258
|
+
sh "./script/puppetca --sign #{hostname}"
|
259
|
+
end
|
260
|
+
|
261
|
+
task :clean do
|
262
|
+
# remove pending request
|
263
|
+
sh "rm -f ssl/ca/requests/#{hostname}*.pem"
|
264
|
+
# remove signed certificat
|
265
|
+
sh "./script/puppetca --clean #{hostname} || true"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def start(options = {})
|
272
|
+
options = {
|
273
|
+
:daemonize => true,
|
274
|
+
:snapshot => ENV['SNAPSHOT'],
|
275
|
+
:hda => disk_image,
|
276
|
+
:nographic => false,
|
277
|
+
:m => memory_size,
|
278
|
+
:net => ["nic", "tap,ifname=#{tap_device}"]
|
279
|
+
}.update(options)
|
280
|
+
|
281
|
+
if options[:daemonize]
|
282
|
+
options = {
|
283
|
+
:pidfile => File.expand_path("tmp/run/#{name}.pid"), :serial => "file:" + File.expand_path("log/#{name}.log")
|
284
|
+
}.update(options)
|
285
|
+
end
|
286
|
+
|
287
|
+
options_as_string = options.collect do |name,value|
|
288
|
+
argument = "-#{name}"
|
289
|
+
|
290
|
+
case value
|
291
|
+
when Array
|
292
|
+
value.collect { |v| "#{argument} '#{v}'" }
|
293
|
+
when true
|
294
|
+
argument
|
295
|
+
when false
|
296
|
+
when nil
|
297
|
+
when ''
|
298
|
+
nil
|
299
|
+
else
|
300
|
+
"#{argument} '#{value}'"
|
301
|
+
end
|
302
|
+
end.compact.join(' ')
|
303
|
+
|
304
|
+
qemu_command =
|
305
|
+
case PLATFORM
|
306
|
+
when /x86_64/
|
307
|
+
"qemu-system-x86_64"
|
308
|
+
else
|
309
|
+
"qemu"
|
310
|
+
end
|
311
|
+
|
312
|
+
sh "#{qemu_command} #{options_as_string}"
|
313
|
+
end
|
314
|
+
|
315
|
+
def snapshot(name)
|
316
|
+
sh "qemu-img convert -O qcow2 #{disk_image} #{disk_image(name)}"
|
317
|
+
end
|
318
|
+
|
319
|
+
def wait(timeout = 30, max_try_count = 5)
|
320
|
+
try_count = 5
|
321
|
+
try_timeout = timeout / try_count
|
322
|
+
|
323
|
+
5.times do
|
324
|
+
if Ping.pingecho(ip_address, try_timeout)
|
325
|
+
return
|
326
|
+
else
|
327
|
+
sleep try_timeout
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
raise "no response from #{hostname} after #{timeout} seconds"
|
332
|
+
end
|
333
|
+
|
334
|
+
def mount(&block)
|
335
|
+
begin
|
336
|
+
mount_image
|
337
|
+
yield mount_point
|
338
|
+
ensure
|
339
|
+
umount_image
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def mount_image
|
344
|
+
sudo "mkdir #{mount_point}" unless File.exists? mount_point
|
345
|
+
sudo "mount -o loop,offset=#{fs_offset} #{disk_image} #{mount_point}"
|
346
|
+
|
347
|
+
sudo "mount proc #{mount_point}/proc -t proc" if File.exists? "#{mount_point}/proc"
|
348
|
+
end
|
349
|
+
|
350
|
+
def umount_image
|
351
|
+
[ "#{mount_point}/proc", mount_point ].each do |mount|
|
352
|
+
sudo "umount #{mount} || true"
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
# TODO to be customizable
|
357
|
+
|
358
|
+
def disk_image(suffix = nil)
|
359
|
+
suffix = "-#{suffix}" if suffix
|
360
|
+
File.join Sandbox.images_directory, "#{name}#{suffix}.img"
|
361
|
+
end
|
362
|
+
|
363
|
+
def fs_offset
|
364
|
+
32256
|
365
|
+
end
|
366
|
+
|
367
|
+
def hostname
|
368
|
+
if name =~ /^sandbox/
|
369
|
+
name
|
370
|
+
else
|
371
|
+
"sandbox-#{name}"
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def tap_device_exists?
|
376
|
+
IO.readlines('/proc/net/dev').any? { |l| l =~ /\s+#{tap_device}/ }
|
377
|
+
end
|
378
|
+
|
379
|
+
def status
|
380
|
+
puts "#{hostname} status:"
|
381
|
+
puts self.inspect
|
382
|
+
end
|
383
|
+
|
384
|
+
def chroot_sh(cmd)
|
385
|
+
sudo "chroot #{mount_point} sh -c \"#{cmd}\""
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
389
|
+
|
390
|
+
class DebianBoostraper
|
391
|
+
|
392
|
+
attr_accessor :version, :mirror, :include, :exclude, :architecture
|
393
|
+
|
394
|
+
def initialize(&block)
|
395
|
+
default_attributes
|
396
|
+
|
397
|
+
@include = %w{puppet ssh udev resolvconf}
|
398
|
+
@exclude = %w{syslinux at exim mailx libstdc++2.10-glibc2.2 mbr setserial fdutils info ipchains iptables lilo pcmcia-cs ppp pppoe pppoeconf pppconfig telnet exim4 exim4-base exim4-config exim4-daemon-light pciutils modconf tasksel console-common console-tools console-data base-config man-db manpages}
|
399
|
+
|
400
|
+
yield self if block_given?
|
401
|
+
end
|
402
|
+
|
403
|
+
def default_attributes
|
404
|
+
@version = 'lenny'
|
405
|
+
@mirror = 'http://ftp.debian.org/debian'
|
406
|
+
@architecture = Sandbox.default_architecture
|
407
|
+
end
|
408
|
+
|
409
|
+
def bootstrap(root)
|
410
|
+
options_as_string = options.collect{|k,v| "--#{k} #{Array(v).join(',')}"}.join(' ')
|
411
|
+
sudo "debootstrap #{options_as_string} #{version} #{root} #{mirror}"
|
412
|
+
end
|
413
|
+
|
414
|
+
def options
|
415
|
+
{
|
416
|
+
:arch => architecture,
|
417
|
+
:exclude => @exclude,
|
418
|
+
:include => @include
|
419
|
+
}
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
class UbuntuBoostraper < DebianBoostraper
|
425
|
+
|
426
|
+
def default_attributes
|
427
|
+
super
|
428
|
+
|
429
|
+
@version = 'intrepid'
|
430
|
+
@mirror = 'http://archive.ubuntu.com/ubuntu/'
|
431
|
+
end
|
432
|
+
|
433
|
+
def options
|
434
|
+
super.update :components => 'main,universe'
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|