toft 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/toft.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'toft/node_controller'
2
+ require 'toft/file_checker'
3
+ require 'toft/chef/chef_attributes'
4
+ require 'toft/chef/chef_runner'
5
+
6
+ module Toft
7
+ class << self
8
+ attr_accessor :cookbook_path, :role_path
9
+ end
10
+
11
+ def create_node(hostname, ip)
12
+ NodeController.instance.create_node(hostname, ip)
13
+ end
14
+
15
+ def find(hostname)
16
+ NodeController.instance.nodes[hostname]
17
+ end
18
+
19
+ def destroy_node(hostname)
20
+ NodeController.instance.destroy_node(hostname)
21
+ end
22
+
23
+ def node_count
24
+ NodeController.instance.nodes.size
25
+ end
26
+ end
27
+
28
+ class NilClass
29
+ def blank?
30
+ true
31
+ end
32
+ end
33
+
34
+ class String
35
+ def blank?
36
+ empty?
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ echo "deb http://apt.opscode.com/ `lsb_release -cs`-0.10 main" | tee /etc/apt/sources.list.d/opscode.list
2
+
3
+ mkdir -p /etc/apt/trusted.gpg.d
4
+ gpg --keyserver keys.gnupg.net --recv-keys 83EF826A
5
+ gpg --export packages@opscode.com | tee /etc/apt/trusted.gpg.d/opscode-keyring.gpg > /dev/null
6
+ apt-get update
7
+ apt-get install ucf --force-yes -y
8
+ yes | apt-get install opscode-keyring --force-yes -y # permanent upgradeable keyring
9
+
10
+ export DEBIAN_FRONTEND=noninteractive
11
+ apt-get install chef --force-yes -qy
@@ -0,0 +1,79 @@
1
+ function load_rvm {
2
+ cat <<-EOF >> ~/.profile
3
+ [[ -s ~/.rvm/scripts/rvm ]] && . ~/.rvm/scripts/rvm
4
+ EOF
5
+ . ~/.profile
6
+ }
7
+
8
+ function install_rvm {
9
+ log "installing rvm"
10
+ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
11
+ echo 'export rvm_project_rvmrc=1' >> $HOME/.rvmrc
12
+ load_rvm
13
+ }
14
+
15
+ function check_rvm {
16
+ load_rvm
17
+ hash rvm || install_rvm
18
+ log "rvm installed"
19
+ }
20
+
21
+ function fix_rvm_readline_for_macos_tiger {
22
+ if [[ `uname` == 'Darwin' ]] && [[ `uname -r` == 11* ]]; then
23
+ (cd "$HOME/.rvm/src/readline-6.0" && \
24
+ sed -i "" -e"s/darwin\[89\]\*\|darwin10\*/darwin\[89\]\*\|darwin1\[01\]\*/g" support/shobj-conf && \
25
+ ./configure --prefix="$HOME/.rvm/usr/" && \
26
+ make clean && \
27
+ make && \
28
+ make install)
29
+ fi
30
+ }
31
+
32
+ function install_xslt {
33
+ [[ -d "$HOME/.rvm/usr/include/libxslt" ]] || \
34
+ ( cd /tmp && \
35
+ rm -rf libxslt-1.1.26 && \
36
+ wget -c ftp://xmlsoft.org/libxml2/libxslt-1.1.26.tar.gz && \
37
+ tar -zxvf libxslt-1.1.26.tar.gz && \
38
+ cd libxslt-1.1.26 && \
39
+ ./configure --prefix="$HOME/.rvm/usr" --with-libxml-prefix="$HOME/.rvm/usr" && \
40
+ make && \
41
+ make install )
42
+ }
43
+
44
+ function install_ruby {
45
+ log "installing ruby"
46
+ rvm pkg install libxml2 && \
47
+ rvm pkg install openssl && \
48
+ rvm pkg install ncurses && \
49
+ rvm pkg install readline && \
50
+ fix_rvm_readline_for_macos_tiger && \
51
+ install_xslt && \
52
+ rvm install ruby-1.8.7-p352 -C "--with-readline-dir=$HOME/.rvm/usr --with-xml-dir=$HOME/.rvm/usr --with-openssl-dir=$HOME/.rvm/usr" && \
53
+ rvm use 1.8.7-p352 &&
54
+ }
55
+
56
+ function check_ruby {
57
+ rvm list | grep 1.8.7-p352 > /dev/null || install_ruby
58
+ log "ruby installed"
59
+ }
60
+
61
+ function install_bundler {
62
+ log "installing bundler"
63
+ gem sources | grep "http://rubygems.org/" || gem sources -a http://rubygems.org/ && \
64
+ gem sources | grep "http://gems.rubyforge.org/" || gem sources -a http://gems.rubyforge.org/ && \
65
+ gem install bundler --no-ri --no-rdoc
66
+ }
67
+
68
+ function check_bundler {
69
+ which bundle | grep 1.8.7-p352 > /dev/null || install_bundler
70
+ log "bundler installed"
71
+ }
72
+
73
+ function ruby_environment {
74
+ check_rvm && \
75
+ check_ruby && \
76
+ check_bundler
77
+ }
78
+
79
+ ruby_environment
@@ -0,0 +1 @@
1
+ default[:network][:gateway_ip] = "192.168.20.1"
@@ -0,0 +1,61 @@
1
+ #!/bin/bash
2
+
3
+ cache="/var/cache/lxc/ubuntu"
4
+ suite=lucid
5
+
6
+ arch=$(arch)
7
+ if [ "$arch" == "x86_64" ]; then
8
+ arch=amd64
9
+ fi
10
+
11
+ if [ "$arch" == "i686" ]; then
12
+ arch=i386
13
+ fi
14
+
15
+ if [ -e "$cache/$suite-$arch.tar.gz" ]; then
16
+ echo "Cache rootfs already exists!"
17
+ exit 0
18
+ fi
19
+
20
+ chef_packages=ruby,rubygems1.8,ruby-dev,libopenssl-ruby,build-essential,wget,ssl-cert
21
+ packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,dhcp3-client,ssh,lsb-release,wget,gpgv,gnupg,sudo,$chef_packages
22
+
23
+ # check the mini ubuntu was not already downloaded
24
+ mkdir -p "$cache/partial-$arch"
25
+ if [ $? -ne 0 ]; then
26
+ echo "Failed to create '$cache/partial-$arch' directory"
27
+ exit 1
28
+ fi
29
+
30
+ # download a mini ubuntu into a cache
31
+ echo "Downloading ubuntu minimal ..."
32
+ debootstrap --verbose --variant=minbase --components=main,universe --arch=$arch --include=$packages $suite $cache/partial-$arch
33
+ if [ $? -ne 0 ]; then
34
+ echo "Failed to download the rootfs, aborting."
35
+ exit 1
36
+ fi
37
+
38
+ mv "$cache/partial-$arch" "$cache/rootfs-$arch"
39
+ echo "Download complete."
40
+
41
+ # install chef
42
+ cat <<EOF > "$cache/rootfs-$arch/tmp/install-chef-ubuntu.sh"
43
+ echo "deb http://apt.opscode.com/ $suite-0.10 main" | tee /etc/apt/sources.list.d/opscode.list
44
+
45
+ mkdir -p /etc/apt/trusted.gpg.d
46
+ gpg --keyserver keys.gnupg.net --recv-keys 83EF826A
47
+ gpg --export packages@opscode.com | tee /etc/apt/trusted.gpg.d/opscode-keyring.gpg > /dev/null
48
+ apt-get update
49
+ apt-get install ucf --force-yes -y
50
+ yes | apt-get install opscode-keyring --force-yes -y # permanent upgradeable keyring
51
+
52
+ export DEBIAN_FRONTEND=noninteractive
53
+ apt-get install chef --force-yes -qy
54
+ EOF
55
+ chroot "$cache/rootfs-$arch" bash /tmp/install-chef-ubuntu.sh
56
+
57
+ # compress root image
58
+ (cd $cache/rootfs-$arch && tar zcf $suite-$arch.tar.gz .)
59
+ mv $cache/rootfs-$arch/$suite-$arch.tar.gz $cache
60
+
61
+
@@ -0,0 +1,42 @@
1
+ %w{lxc bridge-utils debootstrap}.each do |pkg|
2
+ package "#{pkg}"
3
+ end
4
+
5
+ bash "set up networking" do
6
+ code <<-EOH
7
+ brctl addbr br0
8
+ ifconfig br0 #{node.network.gateway_ip} netmask 255.255.255.0 up
9
+ iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
10
+ sysctl -w net.ipv4.ip_forward=1
11
+ EOH
12
+ not_if "ip link ls dev br0"
13
+ end
14
+
15
+ directory "/cgroup" do
16
+ action :create
17
+ end
18
+
19
+ mount "/cgroup" do
20
+ device "cgroup"
21
+ fstype "cgroup"
22
+ pass 0
23
+ action [:mount, :enable]
24
+ end
25
+
26
+ template "/usr/lib/lxc/templates/lxc-lucid-chef" do
27
+ source "lxc-lucid-chef"
28
+ mode "0755"
29
+ action :create
30
+ end
31
+
32
+ cookbook_file "/usr/local/bin/lxc-create-ubuntu-image" do
33
+ source "lxc-create-ubuntu-image"
34
+ mode "0755"
35
+ end
36
+
37
+ bash "create ubuntu rootfs image ... this will take a while" do
38
+ code <<-EOH
39
+ /usr/local/bin/lxc-create-ubuntu-image
40
+ EOH
41
+ end
42
+
@@ -0,0 +1,328 @@
1
+ #!/bin/bash
2
+
3
+ configure_ubuntu()
4
+ {
5
+ rootfs=$1
6
+ hostname=$2
7
+
8
+ # add host root ssh access
9
+ mkdir $rootfs/root/.ssh
10
+ chmod 0600 $rootfs/root/.ssh
11
+ cat <<-EOF > $rootfs/root/.ssh/authorized_keys
12
+ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCguB7XL3ARzLZYLsIMZe4UUO371m+H5C6V8MhtmSlgXtgHDo7eZhNSm5zCeoyGd32OKeLxuxCCEkXfDDF1aa2a6twcASE3pmWNdnBS7auiOH4P7g+eQ4Aw9v7DdESbIVgHF/NDiAEFFdmApYNM3oCX2FhEVNVKxkkIokUr4axYFJzmJ6Xoi5Sd8JtPC85FZVXqDucZDnHQlOcCkbSo0UOmsWQGwtu8eUHoDeUG0dB8ntb9xlBeLctdrAPhuFYCX8IfFkdcakkzv61ETPbKE6g9wdTDC/TEep7/AHGYmarziRnwKiVOL1jnE1coOJLqy8wOC3dKGmRZy9D4sTc+FRV root insecure public key
13
+ EOF
14
+
15
+ # copy host resolve
16
+ rm $rootfs/etc/resolv.conf
17
+ cp /etc/resolv.conf $rootfs/etc/resolv.conf
18
+
19
+ # add default route to host
20
+ cat <<EOF > $rootfs/etc/rc.local
21
+ #!/bin/sh -e
22
+ route add default gw <%= node.network.gateway_ip %>
23
+ exit 0
24
+ EOF
25
+
26
+ # disable selinux in ubuntu
27
+ mkdir -p $rootfs/selinux
28
+ echo 0 > $rootfs/selinux/enforce
29
+
30
+ # set the hostname
31
+ cat <<EOF > $rootfs/etc/hostname
32
+ $hostname
33
+ EOF
34
+ # set minimal hosts
35
+ cat <<EOF > $rootfs/etc/hosts
36
+ 127.0.0.1 localhost $hostname
37
+ EOF
38
+
39
+ # provide the lxc service
40
+ cat <<EOF > $rootfs/etc/init/lxc.conf
41
+ # fake some events needed for correct startup other services
42
+
43
+ description "Container Upstart"
44
+
45
+ start on startup
46
+
47
+ script
48
+ rm -rf /var/run/*.pid
49
+ rm -rf /var/run/network/*
50
+ /sbin/initctl emit stopped JOB=udevtrigger --no-wait
51
+ /sbin/initctl emit started JOB=udev --no-wait
52
+ end script
53
+ EOF
54
+
55
+ # fix buggus runlevel with sshd
56
+ cat <<EOF > $rootfs/etc/init/ssh.conf
57
+ # ssh - OpenBSD Secure Shell server
58
+ #
59
+ # The OpenSSH server provides secure shell access to the system.
60
+
61
+ description "OpenSSH server"
62
+
63
+ start on filesystem
64
+ stop on runlevel [!2345]
65
+
66
+ expect fork
67
+ respawn
68
+ respawn limit 10 5
69
+ umask 022
70
+ # replaces SSHD_OOM_ADJUST in /etc/default/ssh
71
+ oom never
72
+
73
+ pre-start script
74
+ test -x /usr/sbin/sshd || { stop; exit 0; }
75
+ test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
76
+ test -c /dev/null || { stop; exit 0; }
77
+
78
+ mkdir -p -m0755 /var/run/sshd
79
+ end script
80
+
81
+ # if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
82
+ # 'exec' line here instead
83
+ exec /usr/sbin/sshd
84
+ EOF
85
+
86
+ cat <<EOF > $rootfs/etc/init/console.conf
87
+ # console - getty
88
+ #
89
+ # This service maintains a console on tty1 from the point the system is
90
+ # started until it is shut down again.
91
+
92
+ start on stopped rc RUNLEVEL=[2345]
93
+ stop on runlevel [!2345]
94
+
95
+ respawn
96
+ exec /sbin/getty -8 38400 /dev/console
97
+ EOF
98
+
99
+ cat <<EOF > $rootfs/lib/init/fstab
100
+ # /lib/init/fstab: lxc system fstab
101
+ none /spu spufs gid=spu,optional 0 0
102
+ none /tmp none defaults 0 0
103
+ none /var/lock tmpfs nodev,noexec,nosuid,showthrough 0 0
104
+ none /lib/init/rw tmpfs mode=0755,nosuid,optional 0 0
105
+ EOF
106
+
107
+
108
+
109
+ # reconfigure some services
110
+ if [ -z "$LANG" ]; then
111
+ chroot $rootfs locale-gen en_US.UTF-8
112
+ chroot $rootfs update-locale LANG=en_US.UTF-8
113
+ else
114
+ chroot $rootfs locale-gen $LANG
115
+ chroot $rootfs update-locale LANG=$LANG
116
+ fi
117
+
118
+ # remove pointless services in a container
119
+ chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
120
+
121
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
122
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
123
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
124
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
125
+ chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
126
+
127
+ echo "Set root password to 'root'"
128
+ echo "root:root" | chroot $rootfs chpasswd
129
+
130
+ return 0
131
+ }
132
+
133
+ copy_ubuntu()
134
+ {
135
+ cache=$1
136
+ arch=$2
137
+ rootfs=$3
138
+
139
+ # make a local copy of the miniubuntu
140
+ echo -n "Extracting rootfs image to $rootfs ..."
141
+ mkdir $rootfs
142
+ tar zxf $cache/lucid-$arch.tar.gz -C $rootfs || return 1
143
+ return 0
144
+ }
145
+
146
+ install_ubuntu()
147
+ {
148
+ cache="/var/cache/lxc/ubuntu"
149
+ rootfs=$1
150
+ mkdir -p /var/lock/subsys/
151
+ (
152
+ flock -n -x 200
153
+ if [ $? -ne 0 ]; then
154
+ echo "Cache repository is busy."
155
+ return 1
156
+ fi
157
+
158
+ arch=$(arch)
159
+ if [ "$arch" == "x86_64" ]; then
160
+ arch=amd64
161
+ fi
162
+
163
+ if [ "$arch" == "i686" ]; then
164
+ arch=i386
165
+ fi
166
+
167
+ echo "Checking image cache in $cache/rootfs-$arch ... "
168
+ if [ ! -e "$cache/rootfs-$arch" ]; then
169
+ if [ $? -ne 0 ]; then
170
+ echo "Failed to download 'ubuntu base'"
171
+ return 1
172
+ fi
173
+ fi
174
+
175
+ copy_ubuntu $cache $arch $rootfs
176
+ if [ $? -ne 0 ]; then
177
+ echo "Failed to copy rootfs"
178
+ return 1
179
+ fi
180
+
181
+ return 0
182
+
183
+ ) 200>/var/lock/subsys/lxc
184
+
185
+ return $?
186
+ }
187
+
188
+ copy_configuration()
189
+ {
190
+ path=$1
191
+ rootfs=$2
192
+ name=$3
193
+
194
+ cat <<EOF >> $path/config
195
+ lxc.utsname = $name
196
+
197
+ lxc.tty = 4
198
+ lxc.pts = 1024
199
+ lxc.rootfs = $rootfs
200
+ lxc.mount = $path/fstab
201
+
202
+ lxc.cgroup.devices.deny = a
203
+ # /dev/null and zero
204
+ lxc.cgroup.devices.allow = c 1:3 rwm
205
+ lxc.cgroup.devices.allow = c 1:5 rwm
206
+ # consoles
207
+ lxc.cgroup.devices.allow = c 5:1 rwm
208
+ lxc.cgroup.devices.allow = c 5:0 rwm
209
+ lxc.cgroup.devices.allow = c 4:0 rwm
210
+ lxc.cgroup.devices.allow = c 4:1 rwm
211
+ # /dev/{,u}random
212
+ lxc.cgroup.devices.allow = c 1:9 rwm
213
+ lxc.cgroup.devices.allow = c 1:8 rwm
214
+ lxc.cgroup.devices.allow = c 136:* rwm
215
+ lxc.cgroup.devices.allow = c 5:2 rwm
216
+ # rtc
217
+ lxc.cgroup.devices.allow = c 254:0 rwm
218
+ EOF
219
+
220
+ cat <<EOF > $path/fstab
221
+ proc $rootfs/proc proc nodev,noexec,nosuid 0 0
222
+ devpts $rootfs/dev/pts devpts defaults 0 0
223
+ sysfs $rootfs/sys sysfs defaults 0 0
224
+ EOF
225
+
226
+ if [ $? -ne 0 ]; then
227
+ echo "Failed to add configuration"
228
+ return 1
229
+ fi
230
+
231
+ return 0
232
+ }
233
+
234
+ clean()
235
+ {
236
+ cache="/var/cache/lxc/ubuntu"
237
+
238
+ if [ ! -e $cache ]; then
239
+ exit 0
240
+ fi
241
+
242
+ # lock, so we won't purge while someone is creating a repository
243
+ (
244
+ flock -n -x 200
245
+ if [ $? != 0 ]; then
246
+ echo "Cache repository is busy."
247
+ exit 1
248
+ fi
249
+
250
+ echo -n "Purging the download cache..."
251
+ rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
252
+ exit 0
253
+
254
+ ) 200>/var/lock/subsys/lxc
255
+ }
256
+
257
+ usage()
258
+ {
259
+ cat <<EOF
260
+ $1 -h|--help -p|--path=<path> --clean
261
+ EOF
262
+ return 0
263
+ }
264
+
265
+ options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
266
+ if [ $? -ne 0 ]; then
267
+ usage $(basename $0)
268
+ exit 1
269
+ fi
270
+ eval set -- "$options"
271
+
272
+ while true
273
+ do
274
+ case "$1" in
275
+ -h|--help) usage $0 && exit 0;;
276
+ -p|--path) path=$2; shift 2;;
277
+ -n|--name) name=$2; shift 2;;
278
+ -c|--clean) clean=$2; shift 2;;
279
+ --) shift 1; break ;;
280
+ *) break ;;
281
+ esac
282
+ done
283
+
284
+ if [ ! -z "$clean" -a -z "$path" ]; then
285
+ clean || exit 1
286
+ exit 0
287
+ fi
288
+
289
+ type debootstrap
290
+ if [ $? -ne 0 ]; then
291
+ echo "'debootstrap' command is missing"
292
+ exit 1
293
+ fi
294
+
295
+ if [ -z "$path" ]; then
296
+ echo "'path' parameter is required"
297
+ exit 1
298
+ fi
299
+
300
+ if [ "$(id -u)" != "0" ]; then
301
+ echo "This script should be run as 'root'"
302
+ exit 1
303
+ fi
304
+
305
+ rootfs=$path/rootfs
306
+
307
+ install_ubuntu $rootfs
308
+ if [ $? -ne 0 ]; then
309
+ echo "failed to install ubuntu"
310
+ exit 1
311
+ fi
312
+
313
+ configure_ubuntu $rootfs $name
314
+ if [ $? -ne 0 ]; then
315
+ echo "failed to configure ubuntu for a container"
316
+ exit 1
317
+ fi
318
+
319
+ copy_configuration $path $rootfs $name
320
+ if [ $? -ne 0 ]; then
321
+ echo "failed write configuration file"
322
+ exit 1
323
+ fi
324
+
325
+ if [ ! -z $clean ]; then
326
+ clean || exit 1
327
+ exit 0
328
+ fi
@@ -0,0 +1,4 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'toft/chef/chef_attributes'
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'cucumber/ast/table'
3
+
4
+ describe "ChefAttributes" do
5
+ it "should parse chef dot connected attributes" do
6
+ ca = Toft::ChefAttributes.new(Cucumber::Ast::Table.new([[]]))
7
+ ca.add_attribute "one.two.three", "some"
8
+ ca.add_attribute "one.four", "another"
9
+ ca.attributes["one"]["two"]["three"].should == "some"
10
+ ca.attributes["one"]["four"].should == "another"
11
+ end
12
+
13
+ it "should parse cucumber chef attributes ast table" do
14
+ table = Cucumber::Ast::Table.new([
15
+ ["key", "value"],
16
+ ["one.four", "one"],
17
+ ["one.two.three", "some"]
18
+ ])
19
+ ca = Toft::ChefAttributes.new(table)
20
+ ca.attributes["one"]["four"].should == "one"
21
+ ca.attributes["one"]["two"]["three"].should == "some"
22
+ end
23
+
24
+ it "should return json" do
25
+ table = Cucumber::Ast::Table.new([
26
+ ["key", "value"],
27
+ ["one.four", "one"],
28
+ ["one.two.three", "some"]
29
+ ])
30
+ ca = Toft::ChefAttributes.new(table)
31
+ ca.to_json.should == "{\"one\":{\"two\":{\"three\":\"some\"},\"four\":\"one\"}}"
32
+ end
33
+ end