vagabond 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +11 -0
- data/README.md +90 -27
- data/lib/vagabond/actions/create.rb +16 -15
- data/lib/vagabond/actions/destroy.rb +18 -7
- data/lib/vagabond/actions/freeze.rb +9 -4
- data/lib/vagabond/actions/provision.rb +20 -8
- data/lib/vagabond/actions/rebuild.rb +18 -0
- data/lib/vagabond/actions/ssh.rb +8 -3
- data/lib/vagabond/actions/start.rb +18 -0
- data/lib/vagabond/actions/status.rb +23 -6
- data/lib/vagabond/actions/thaw.rb +9 -4
- data/lib/vagabond/actions/up.rb +10 -16
- data/lib/vagabond/commands.rb +40 -11
- data/lib/vagabond/cookbooks/lxc/libraries/lxc.rb +57 -25
- data/lib/vagabond/cookbooks/lxc/providers/container.rb +1 -0
- data/lib/vagabond/cookbooks/lxc/resources/container.rb +1 -0
- data/lib/vagabond/cookbooks/vagabond/attributes/default.rb +10 -0
- data/lib/vagabond/cookbooks/vagabond/files/default/lxc-centos +453 -0
- data/lib/vagabond/cookbooks/vagabond/recipes/default.rb +30 -3
- data/lib/vagabond/helpers.rb +18 -0
- data/lib/vagabond/internal_configuration.rb +18 -13
- data/lib/vagabond/knife.rb +36 -0
- data/lib/vagabond/server.rb +88 -81
- data/lib/vagabond/vagabond.rb +20 -15
- data/lib/vagabond/version.rb +1 -1
- data/vagabond-0.1.0.gem +0 -0
- metadata +8 -3
- data/lib/vagabond/cookbooks/vagabond/recipes/create.rb +0 -3
data/lib/vagabond/actions/up.rb
CHANGED
@@ -2,24 +2,18 @@ module Vagabond
|
|
2
2
|
module Actions
|
3
3
|
module Up
|
4
4
|
def up
|
5
|
-
if(
|
6
|
-
|
7
|
-
|
5
|
+
if(lxc.exists?)
|
6
|
+
if(lxc.running?)
|
7
|
+
ui.error "Node already exists and is running: #{name}"
|
8
|
+
else
|
9
|
+
ui.info "#{ui.color('Vagabond:', :bold)} Starting node: #{ui.color(name, :green)}"
|
10
|
+
lxc.start
|
11
|
+
ui.info ui.color(' -> STARTED', :green)
|
12
|
+
end
|
8
13
|
else
|
9
|
-
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def do_start
|
16
|
-
if(lxc.running?)
|
17
|
-
ui.error "LXC: #{name} is already running!"
|
18
|
-
else
|
19
|
-
do_create
|
20
|
-
ui.info "LXC: #{name} has been started!"
|
21
|
-
do_provision unless Config[:disable_auto_provision]
|
14
|
+
create
|
22
15
|
end
|
16
|
+
do_provision unless Config[:disable_auto_provision]
|
23
17
|
end
|
24
18
|
|
25
19
|
end
|
data/lib/vagabond/commands.rb
CHANGED
@@ -1,25 +1,39 @@
|
|
1
1
|
require 'mixlib/cli'
|
2
|
+
require 'chef/log'
|
2
3
|
require 'vagabond/config'
|
3
4
|
require 'vagabond/vagabond'
|
4
5
|
require 'vagabond/server'
|
6
|
+
require 'vagabond/knife'
|
5
7
|
|
6
8
|
module Vagabond
|
7
9
|
class Commands
|
8
10
|
|
9
11
|
include Mixlib::CLI
|
12
|
+
|
13
|
+
DEFAULT_ACTIONS = Actions.constants.map do |konst|
|
14
|
+
const = Actions.const_get(konst)
|
15
|
+
const.public_instance_methods(false) if const.is_a?(Module)
|
16
|
+
end.flatten.sort
|
10
17
|
|
11
|
-
|
12
|
-
|
18
|
+
banner(
|
19
|
+
(
|
20
|
+
%w(Nodes:) + DEFAULT_ACTIONS.map{ |cmd|
|
21
|
+
"\tvagabond #{cmd} NODE [options]"
|
22
|
+
}.compact + %w(Server:) + (DEFAULT_ACTIONS + Server.public_instance_methods(false)).sort.map{ |cmd|
|
23
|
+
next if cmd == 'server'
|
24
|
+
"\tvagabond server #{cmd} [options]"
|
25
|
+
}.compact + ['Knife:', "\tvagabond knife COMMAND [knife_options]"] + %w(Options:)
|
26
|
+
).join("\n")
|
13
27
|
)
|
14
|
-
|
28
|
+
|
15
29
|
option(:force_solo,
|
16
|
-
:long => '--force-
|
30
|
+
:long => '--force-configure',
|
17
31
|
:boolean => true,
|
18
32
|
:default => false
|
19
33
|
)
|
20
34
|
|
21
35
|
option(:disable_solo,
|
22
|
-
:long => '--disable-
|
36
|
+
:long => '--disable-configure',
|
23
37
|
:boolean => true,
|
24
38
|
:default => false
|
25
39
|
)
|
@@ -40,18 +54,33 @@ module Vagabond
|
|
40
54
|
:boolean => true,
|
41
55
|
:default => false
|
42
56
|
)
|
57
|
+
|
58
|
+
option(:debug,
|
59
|
+
:long => '--debug',
|
60
|
+
:boolean => true,
|
61
|
+
:default => false
|
62
|
+
)
|
63
|
+
|
64
|
+
option(:color,
|
65
|
+
:long => '--color',
|
66
|
+
:boolean => true
|
67
|
+
)
|
43
68
|
|
44
69
|
def run!(argv)
|
70
|
+
# Turn off Chef logging since we will deal with
|
71
|
+
# our own output
|
72
|
+
Chef::Log.init('/dev/null')
|
45
73
|
parse_options
|
46
74
|
name_args = parse_options(argv)
|
47
|
-
unless(VALID_COMMANDS.include?(name_args.first))
|
48
|
-
raise ArgumentError.new('Invalid command provided!')
|
49
|
-
end
|
50
75
|
Config.merge!(config)
|
51
|
-
if
|
52
|
-
|
76
|
+
Config[:debug] = STDOUT if Config[:debug]
|
77
|
+
case name_args.first.to_s
|
78
|
+
when 'server'
|
79
|
+
Server.new(name_args.shift, name_args).send(:execute)
|
80
|
+
when 'knife'
|
81
|
+
Knife.new(name_args.shift, name_args).send(:execute)
|
53
82
|
else
|
54
|
-
Vagabond.new(name_args.shift, name_args).execute
|
83
|
+
Vagabond.new(name_args.shift, name_args).send(:execute)
|
55
84
|
end
|
56
85
|
end
|
57
86
|
end
|
@@ -107,25 +107,27 @@ class Lxc
|
|
107
107
|
# retries:: Number of discovery attempt (3 second sleep intervals)
|
108
108
|
# Returns container IP
|
109
109
|
def container_ip(retries=0, raise_on_fail=false)
|
110
|
-
retries.to_i.times do
|
111
|
-
ip = hw_detected_address || leased_address || lxc_stored_address
|
110
|
+
(retries.to_i + 1).times do
|
111
|
+
ip = proc_detected_address || hw_detected_address || leased_address || lxc_stored_address
|
112
112
|
return ip if ip && self.class.connection_alive?(ip)
|
113
113
|
Chef::Log.warn "LXC IP discovery: Failed to detect live IP"
|
114
|
-
sleep(3)
|
114
|
+
sleep(3) if retries > 0
|
115
115
|
end
|
116
116
|
raise "Failed to detect live IP address for container: #{name}" if raise_on_fail
|
117
117
|
end
|
118
118
|
|
119
119
|
# Container address via lxc config file
|
120
120
|
def lxc_stored_address
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
121
|
+
if(File.exists?(container_config))
|
122
|
+
ip = File.readlines(container_config).detect{|line|
|
123
|
+
line.include?('ipv4')
|
124
|
+
}.to_s.split('=').last.to_s.strip
|
125
|
+
if(ip.to_s.empty?)
|
126
|
+
nil
|
127
|
+
else
|
128
|
+
Chef::Log.info "LXC Discovery: Found container address via storage: #{ip}"
|
129
|
+
ip
|
130
|
+
end
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
@@ -151,19 +153,36 @@ class Lxc
|
|
151
153
|
def hw_detected_address
|
152
154
|
hw = File.readlines(container_config).detect{|line|
|
153
155
|
line.include?('hwaddr')
|
154
|
-
}.to_s.split('=').last.to_s.
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
156
|
+
}.to_s.split('=').last.to_s.downcase
|
157
|
+
if(File.exists?(container_config) && !hw.empty?)
|
158
|
+
running? # need to do a list!
|
159
|
+
ip = File.readlines('/proc/net/arp').detect{|line|
|
160
|
+
line.downcase.include?(hw)
|
161
|
+
}.to_s.split(' ').first.to_s.strip
|
162
|
+
if(ip.to_s.empty?)
|
163
|
+
nil
|
164
|
+
else
|
165
|
+
Chef::Log.info "LXC Discovery: Found container address via HW addr: #{ip}"
|
166
|
+
ip
|
167
|
+
end
|
164
168
|
end
|
165
169
|
end
|
166
|
-
|
170
|
+
|
171
|
+
def proc_detected_address(base='/run/netns')
|
172
|
+
if(pid != -1)
|
173
|
+
Dir.mktmpdir do |t_dir|
|
174
|
+
name = File.basename(t_dir)
|
175
|
+
path = File.join(base, name)
|
176
|
+
system("#{sudo}mkdir -p #{base}")
|
177
|
+
system("#{sudo}ln -s /proc/#{pid}/ns/net #{path}")
|
178
|
+
res = %x{#{sudo}ip netns exec #{name} ip -4 addr show scope global | grep inet}
|
179
|
+
system("#{sudo}rm -f #{path}")
|
180
|
+
ip = res.strip.split(' ')[1].to_s.sub(%r{/.*$}, '').strip
|
181
|
+
ip.empty? ? nil : ip
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
167
186
|
def sudo
|
168
187
|
self.class.sudo
|
169
188
|
end
|
@@ -189,6 +208,14 @@ class Lxc
|
|
189
208
|
File.join(container_rootfs, path)
|
190
209
|
end
|
191
210
|
|
211
|
+
def state
|
212
|
+
self.class.info(name)[:state]
|
213
|
+
end
|
214
|
+
|
215
|
+
def pid
|
216
|
+
self.class.info(name)[:pid]
|
217
|
+
end
|
218
|
+
|
192
219
|
# Start the container
|
193
220
|
def start
|
194
221
|
run_command("#{sudo}lxc-start -n #{name} -d")
|
@@ -216,7 +243,11 @@ class Lxc
|
|
216
243
|
# Shutdown the container
|
217
244
|
def shutdown
|
218
245
|
run_command("#{sudo}lxc-shutdown -n #{name}")
|
219
|
-
run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :
|
246
|
+
run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure => true, :timeout => 10)
|
247
|
+
if(running?)
|
248
|
+
container_command('shutdown -h now')
|
249
|
+
run_command("#{sudo}lxc-wait -n #{name} -s STOPPED")
|
250
|
+
end
|
220
251
|
end
|
221
252
|
|
222
253
|
def knife_container(cmd, ip)
|
@@ -239,11 +270,12 @@ class Lxc
|
|
239
270
|
begin
|
240
271
|
shlout = Mixlib::ShellOut.new(cmd,
|
241
272
|
:logger => Chef::Log.logger,
|
242
|
-
:live_stream => STDOUT
|
273
|
+
:live_stream => STDOUT,
|
274
|
+
:timeout => args[:timeout] || 1200
|
243
275
|
)
|
244
276
|
shlout.run_command
|
245
277
|
shlout.error!
|
246
|
-
rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed
|
278
|
+
rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout
|
247
279
|
if(args[:allow_failure])
|
248
280
|
true
|
249
281
|
elsif(retries > 0)
|
@@ -30,6 +30,7 @@ action :create do
|
|
30
30
|
#### Create container
|
31
31
|
execute "lxc create[#{new_resource.name}]" do
|
32
32
|
command "lxc-create -n #{new_resource.name} -t #{new_resource.template} -- #{new_resource.template_opts.to_a.flatten.join(' ')}"
|
33
|
+
environment new_resource.create_environment
|
33
34
|
only_if do
|
34
35
|
!new_resource._lxc.exists? && new_resource.updated_by_last_action(true)
|
35
36
|
end
|
@@ -23,6 +23,7 @@ attribute :initialize_commands, :kind_of => Array, :default => []
|
|
23
23
|
attribute :new_container, :kind_of => [TrueClass, FalseClass], :default => false
|
24
24
|
attribute :template, :kind_of => String, :default => 'ubuntu'
|
25
25
|
attribute :template_opts, :kind_of => Hash, :default => {}
|
26
|
+
attribute :create_environment, :kind_of => Hash, :default => {}
|
26
27
|
attribute :_lxc
|
27
28
|
# TODO: We should ultimately have support for all these templates
|
28
29
|
#attribute :template, :equal_to => %w(busybox debian fedora opensuse sshd ubuntu ubuntu-cloud), :default => 'ubuntu'
|
@@ -1,2 +1,12 @@
|
|
1
1
|
default[:vagabond][:bases][:ubuntu_1204][:template_options] = {'--release' => 'precise'}
|
2
2
|
default[:vagabond][:bases][:ubuntu_1210][:template_options] = {'--release' => 'quantal'}
|
3
|
+
default[:vagabond][:bases][:centos_58][:template] = 'centos'
|
4
|
+
default[:vagabond][:bases][:centos_58][:template_options] = {'--release' => '5', '--releaseminor' => '8'}
|
5
|
+
default[:vagabond][:bases][:centos_63][:template] = 'centos'
|
6
|
+
default[:vagabond][:bases][:centos_63][:template_options] = {'--release' => '6', '--releaseminor' => '3'}
|
7
|
+
default[:vagabond][:bases][:centos_64][:template] = 'centos'
|
8
|
+
default[:vagabond][:bases][:centos_64][:template_options] = {'--release' => '6', '--releaseminor' => '4'}
|
9
|
+
default[:vagabond][:bases][:debian_6][:template] = 'debian'
|
10
|
+
default[:vagabond][:bases][:debian_6][:create_environment] = {'SUITE' => 'squeeze'}
|
11
|
+
default[:vagabond][:bases][:debian_7][:template] = 'debian'
|
12
|
+
default[:vagabond][:bases][:debian_7][:create_environment] = {'SUITE' => 'wheezy'}
|
@@ -0,0 +1,453 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
#
|
4
|
+
# template script for generating CentOS container for LXC
|
5
|
+
#
|
6
|
+
|
7
|
+
#
|
8
|
+
# lxc: linux Container library
|
9
|
+
|
10
|
+
# Authors:
|
11
|
+
# Daniel Lezcano <daniel.lezcano@free.fr>
|
12
|
+
# Ramez Hanna <rhanna@informatiq.org>
|
13
|
+
|
14
|
+
# This library is free software; you can redistribute it and/or
|
15
|
+
# modify it under the terms of the GNU Lesser General Public
|
16
|
+
# License as published by the Free Software Foundation; either
|
17
|
+
# version 2.1 of the License, or (at your option) any later version.
|
18
|
+
|
19
|
+
# This library is distributed in the hope that it will be useful,
|
20
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
21
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
22
|
+
# Lesser General Public License for more details.
|
23
|
+
|
24
|
+
# You should have received a copy of the GNU Lesser General Public
|
25
|
+
# License along with this library; if not, write to the Free Software
|
26
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
27
|
+
|
28
|
+
#Configurations
|
29
|
+
arch=$(arch)
|
30
|
+
cache_base=/var/cache/lxc/centos/$arch
|
31
|
+
default_path=/var/lib/lxc
|
32
|
+
root_password=password
|
33
|
+
|
34
|
+
# is this centos?
|
35
|
+
[ -f /etc/redhat-release ] && is_centos=true
|
36
|
+
|
37
|
+
if [ "$arch" = "i686" ]; then
|
38
|
+
arch=i386
|
39
|
+
fi
|
40
|
+
|
41
|
+
configure_centos()
|
42
|
+
{
|
43
|
+
|
44
|
+
# disable selinux in centos
|
45
|
+
mkdir -p $rootfs_path/selinux
|
46
|
+
echo 0 > $rootfs_path/selinux/enforce
|
47
|
+
|
48
|
+
# configure the network using the dhcp
|
49
|
+
cat <<EOF > ${rootfs_path}/etc/sysconfig/network-scripts/ifcfg-eth0
|
50
|
+
DEVICE=eth0
|
51
|
+
BOOTPROTO=dhcp
|
52
|
+
ONBOOT=yes
|
53
|
+
TYPE=Ethernet
|
54
|
+
USERCTL=yes
|
55
|
+
PEERDNS=yes
|
56
|
+
IPV6INIT=no
|
57
|
+
EOF
|
58
|
+
|
59
|
+
# set the dns
|
60
|
+
# TODO: Probably remove this
|
61
|
+
cat > $rootfs_path/etc/resolv.conf << END
|
62
|
+
# Google public DNS
|
63
|
+
nameserver 8.8.8.8
|
64
|
+
nameserver 8.8.4.4
|
65
|
+
END
|
66
|
+
|
67
|
+
|
68
|
+
# set the hostname
|
69
|
+
cat <<EOF > ${rootfs_path}/etc/sysconfig/network
|
70
|
+
NETWORKING=yes
|
71
|
+
HOSTNAME=${name}
|
72
|
+
EOF
|
73
|
+
|
74
|
+
# set minimal hosts
|
75
|
+
cat <<EOF > $rootfs_path/etc/hosts
|
76
|
+
127.0.0.1 localhost $name
|
77
|
+
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
|
78
|
+
EOF
|
79
|
+
|
80
|
+
sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.sysinit
|
81
|
+
sed -i 's|.sbin.start_udev||' ${rootfs_path}/etc/rc.d/rc.sysinit
|
82
|
+
# don't mount devpts, for pete's sake
|
83
|
+
sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.sysinit
|
84
|
+
sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
|
85
|
+
|
86
|
+
sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
|
87
|
+
sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
|
88
|
+
sed -i 's/^.*dev.pts.*$/#\0/' ${rootfs_path}/etc/rc.d/rc.sysinit
|
89
|
+
|
90
|
+
sed -i 's/^#baseurl/baseurl/g' ${rootfs_path}/etc/yum.repos.d/CentOS-Base.repo
|
91
|
+
sed -i "s/\$releasever/$release.$releaseminor/g" ${rootfs_path}/etc/yum.repos.d/CentOS-Base.repo
|
92
|
+
sed -i '115,126s/^/#/' ${rootfs_path}/etc/rc.d/init.d/halt
|
93
|
+
|
94
|
+
chroot ${rootfs_path} chkconfig udev-post off
|
95
|
+
chroot ${rootfs_path} chkconfig network on
|
96
|
+
|
97
|
+
dev_path="${rootfs_path}/dev"
|
98
|
+
rm -rf $dev_path
|
99
|
+
mkdir -p $dev_path
|
100
|
+
mknod -m 666 ${dev_path}/null c 1 3
|
101
|
+
mknod -m 666 ${dev_path}/zero c 1 5
|
102
|
+
mknod -m 666 ${dev_path}/random c 1 8
|
103
|
+
mknod -m 666 ${dev_path}/urandom c 1 9
|
104
|
+
mkdir -m 755 ${dev_path}/pts
|
105
|
+
mkdir -m 1777 ${dev_path}/shm
|
106
|
+
mknod -m 666 ${dev_path}/tty c 5 0
|
107
|
+
mknod -m 666 ${dev_path}/tty0 c 4 0
|
108
|
+
mknod -m 666 ${dev_path}/tty1 c 4 1
|
109
|
+
mknod -m 666 ${dev_path}/tty2 c 4 2
|
110
|
+
mknod -m 666 ${dev_path}/tty3 c 4 3
|
111
|
+
mknod -m 666 ${dev_path}/tty4 c 4 4
|
112
|
+
mknod -m 600 ${dev_path}/console c 5 1
|
113
|
+
mknod -m 666 ${dev_path}/full c 1 7
|
114
|
+
mknod -m 600 ${dev_path}/initctl p
|
115
|
+
mknod -m 666 ${dev_path}/ptmx c 5 2
|
116
|
+
|
117
|
+
echo "setting root passwd to $root_password"
|
118
|
+
echo "root:$root_password" | chroot $rootfs_path chpasswd
|
119
|
+
|
120
|
+
# specifying this in the initial packages doesn't always work.
|
121
|
+
# echo "installing centos-release package"
|
122
|
+
# if [ ! -f ${rootfs_path}/etc/resolv.conf ]; then
|
123
|
+
# cp /etc/resolv.conf ${rootfs_path}/etc/resolv.conf
|
124
|
+
# remove_resolv=1
|
125
|
+
# fi
|
126
|
+
# chroot ${rootfs_path} rpm --rebuilddb
|
127
|
+
# chroot ${rootfs_path} yum --releasever=${release} -y install centos-release
|
128
|
+
# if [ ! -z $remove_resolv ]; then
|
129
|
+
# rm ${rootfs_path}/etc/resolv.conf
|
130
|
+
# fi
|
131
|
+
|
132
|
+
# silence some needless startup errors
|
133
|
+
touch ${rootfs_path}/etc/fstab
|
134
|
+
|
135
|
+
# give us a console on /dev/console
|
136
|
+
sed -i 's/ACTIVE_CONSOLES=.*$/ACTIVE_CONSOLES="\/dev\/console \/dev\/tty[1-4]"/' \
|
137
|
+
${rootfs_path}/etc/sysconfig/init
|
138
|
+
|
139
|
+
return 0
|
140
|
+
}
|
141
|
+
|
142
|
+
download_centos()
|
143
|
+
{
|
144
|
+
|
145
|
+
# check the mini centos was not already downloaded
|
146
|
+
INSTALL_ROOT=$cache/partial
|
147
|
+
mkdir -p $INSTALL_ROOT
|
148
|
+
if [ $? -ne 0 ]; then
|
149
|
+
echo "Failed to create '$INSTALL_ROOT' directory"
|
150
|
+
return 1
|
151
|
+
fi
|
152
|
+
|
153
|
+
# download a mini centos into a cache
|
154
|
+
echo "Downloading centos minimal ..."
|
155
|
+
YUM="yum --installroot $INSTALL_ROOT -y --nogpgcheck"
|
156
|
+
PKG_LIST="yum initscripts passwd rsyslog vim-minimal dhclient chkconfig"
|
157
|
+
PKG_LIST="$PKG_LIST rootfiles policycoreutils centos-release openssh-server avahi"
|
158
|
+
MIRRORLIST_URL="http://mirrorlist.centos.org/?release=$release.$releaseminor&arch=$arch&repo=os"
|
159
|
+
|
160
|
+
DOWNLOAD_OK=no
|
161
|
+
for trynumber in 1 2 3; do
|
162
|
+
[ $trynumber != 1 ] && echo "Trying again..."
|
163
|
+
MIRROR_URL=$(curl -s -S -f "$MIRRORLIST_URL" | head -n2 | tail -n1)
|
164
|
+
if [ $? -ne 0 ] || [ -z "$MIRROR_URL" ]; then
|
165
|
+
echo "Failed to get a mirror"
|
166
|
+
continue
|
167
|
+
fi
|
168
|
+
RELEASE_URL="$MIRROR_URL/Packages/centos-release-$release-$releaseminor.el6.centos.9.$arch.rpm"
|
169
|
+
echo "Fetching from $RELEASE_URL"
|
170
|
+
curl -f "$RELEASE_URL" > $INSTALL_ROOT/centos-release-$release-$releaseminor.centos.$arch.rpm
|
171
|
+
if [ $? -ne 0 ]; then
|
172
|
+
echo "Failed to download centos release rpm"
|
173
|
+
continue
|
174
|
+
fi
|
175
|
+
DOWNLOAD_OK=yes
|
176
|
+
break
|
177
|
+
done
|
178
|
+
if [ $DOWNLOAD_OK != yes ]; then
|
179
|
+
echo "Aborting"
|
180
|
+
return 1
|
181
|
+
fi
|
182
|
+
|
183
|
+
mkdir -p $INSTALL_ROOT/var/lib/rpm
|
184
|
+
rpm --root $INSTALL_ROOT --initdb
|
185
|
+
rpm --root $INSTALL_ROOT -ivh $INSTALL_ROOT/centos-release-$release-$releaseminor.centos.$arch.rpm
|
186
|
+
$YUM install $PKG_LIST
|
187
|
+
chroot $INSTALL_ROOT rm -f /var/lib/rpm/__*
|
188
|
+
chroot $INSTALL_ROOT rpm --rebuilddb
|
189
|
+
|
190
|
+
if [ $? -ne 0 ]; then
|
191
|
+
echo "Failed to download the rootfs, aborting."
|
192
|
+
return 1
|
193
|
+
fi
|
194
|
+
|
195
|
+
mv "$INSTALL_ROOT" "$cache/rootfs"
|
196
|
+
echo "Download complete."
|
197
|
+
|
198
|
+
return 0
|
199
|
+
}
|
200
|
+
|
201
|
+
copy_centos()
|
202
|
+
{
|
203
|
+
|
204
|
+
# make a local copy of the minicentos
|
205
|
+
echo -n "Copying rootfs to $rootfs_path ..."
|
206
|
+
#cp -a $cache/rootfs-$arch $rootfs_path || return 1
|
207
|
+
# i prefer rsync (no reason really)
|
208
|
+
mkdir -p $rootfs_path
|
209
|
+
rsync -a $cache/rootfs/ $rootfs_path/
|
210
|
+
return 0
|
211
|
+
}
|
212
|
+
|
213
|
+
update_centos()
|
214
|
+
{
|
215
|
+
# chroot $cache/rootfs yum -y update
|
216
|
+
echo "Updates disabled"
|
217
|
+
}
|
218
|
+
|
219
|
+
install_centos()
|
220
|
+
{
|
221
|
+
mkdir -p /var/lock/subsys/
|
222
|
+
(
|
223
|
+
flock -x 200
|
224
|
+
if [ $? -ne 0 ]; then
|
225
|
+
echo "Cache repository is busy."
|
226
|
+
return 1
|
227
|
+
fi
|
228
|
+
|
229
|
+
echo "Checking cache download in $cache/rootfs ... "
|
230
|
+
if [ ! -e "$cache/rootfs" ]; then
|
231
|
+
download_centos
|
232
|
+
if [ $? -ne 0 ]; then
|
233
|
+
echo "Failed to download 'centos base'"
|
234
|
+
return 1
|
235
|
+
fi
|
236
|
+
else
|
237
|
+
echo "Cache found. Updating..."
|
238
|
+
update_centos
|
239
|
+
if [ $? -ne 0 ]; then
|
240
|
+
echo "Failed to update 'centos base', continuing with last known good cache"
|
241
|
+
else
|
242
|
+
echo "Update finished"
|
243
|
+
fi
|
244
|
+
fi
|
245
|
+
|
246
|
+
echo "Copy $cache/rootfs to $rootfs_path ... "
|
247
|
+
copy_centos
|
248
|
+
if [ $? -ne 0 ]; then
|
249
|
+
echo "Failed to copy rootfs"
|
250
|
+
return 1
|
251
|
+
fi
|
252
|
+
|
253
|
+
return 0
|
254
|
+
|
255
|
+
) 200>/var/lock/subsys/lxc
|
256
|
+
|
257
|
+
return $?
|
258
|
+
}
|
259
|
+
|
260
|
+
copy_configuration()
|
261
|
+
{
|
262
|
+
|
263
|
+
mkdir -p $config_path
|
264
|
+
cat <<EOF >> $config_path/config
|
265
|
+
lxc.utsname = $name
|
266
|
+
lxc.tty = 4
|
267
|
+
lxc.pts = 1024
|
268
|
+
lxc.rootfs = $rootfs_path
|
269
|
+
lxc.mount = $config_path/fstab
|
270
|
+
|
271
|
+
# uncomment the next line to run the container unconfined:
|
272
|
+
#lxc.aa_profile = unconfined
|
273
|
+
|
274
|
+
#cgroups
|
275
|
+
lxc.cgroup.devices.deny = a
|
276
|
+
# /dev/null and zero
|
277
|
+
lxc.cgroup.devices.allow = c 1:3 rwm
|
278
|
+
lxc.cgroup.devices.allow = c 1:5 rwm
|
279
|
+
# consoles
|
280
|
+
lxc.cgroup.devices.allow = c 5:1 rwm
|
281
|
+
lxc.cgroup.devices.allow = c 5:0 rwm
|
282
|
+
lxc.cgroup.devices.allow = c 4:0 rwm
|
283
|
+
lxc.cgroup.devices.allow = c 4:1 rwm
|
284
|
+
# /dev/{,u}random
|
285
|
+
lxc.cgroup.devices.allow = c 1:9 rwm
|
286
|
+
lxc.cgroup.devices.allow = c 1:8 rwm
|
287
|
+
lxc.cgroup.devices.allow = c 136:* rwm
|
288
|
+
lxc.cgroup.devices.allow = c 5:2 rwm
|
289
|
+
# rtc
|
290
|
+
lxc.cgroup.devices.allow = c 254:0 rwm
|
291
|
+
EOF
|
292
|
+
|
293
|
+
cat <<EOF > $config_path/fstab
|
294
|
+
proc proc proc nodev,noexec,nosuid 0 0
|
295
|
+
sysfs sys sysfs defaults 0 0
|
296
|
+
EOF
|
297
|
+
if [ $? -ne 0 ]; then
|
298
|
+
echo "Failed to add configuration"
|
299
|
+
return 1
|
300
|
+
fi
|
301
|
+
|
302
|
+
return 0
|
303
|
+
}
|
304
|
+
|
305
|
+
clean()
|
306
|
+
{
|
307
|
+
|
308
|
+
if [ ! -e $cache ]; then
|
309
|
+
exit 0
|
310
|
+
fi
|
311
|
+
|
312
|
+
# lock, so we won't purge while someone is creating a repository
|
313
|
+
(
|
314
|
+
flock -x 200
|
315
|
+
if [ $? != 0 ]; then
|
316
|
+
echo "Cache repository is busy."
|
317
|
+
exit 1
|
318
|
+
fi
|
319
|
+
|
320
|
+
echo -n "Purging the download cache for Centos-$release-$releaseminor..."
|
321
|
+
rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
|
322
|
+
exit 0
|
323
|
+
|
324
|
+
) 200>/var/lock/subsys/lxc
|
325
|
+
}
|
326
|
+
|
327
|
+
usage()
|
328
|
+
{
|
329
|
+
cat <<EOF
|
330
|
+
usage:
|
331
|
+
$1 -n|--name=<container_name>
|
332
|
+
[-p|--path=<path>] [-c|--clean] [-R|--release=<Centos_release>] [-A|--arch=<arch of the container>]
|
333
|
+
[-h|--help]
|
334
|
+
Mandatory args:
|
335
|
+
-n,--name container name, used to as an identifier for that container from now on
|
336
|
+
Optional args:
|
337
|
+
-p,--path path to where the container rootfs will be created, defaults to /var/lib/lxc. The container config will go under /var/lib/lxc in that case
|
338
|
+
-c,--clean clean the cache
|
339
|
+
-R,--release Centos release for the new container. if the host is Fedora, then it will defaultto the host's release.
|
340
|
+
-m,--release-minor Minor release number for the new containar
|
341
|
+
-A,--arch NOT USED YET. Define what arch the container will be [i686,x86_64]
|
342
|
+
-h,--help print this help
|
343
|
+
EOF
|
344
|
+
return 0
|
345
|
+
}
|
346
|
+
|
347
|
+
options=$(getopt -o hp:n:cR:m: -l help,path:,name:,clean,release:,releaseminor: -- "$@")
|
348
|
+
if [ $? -ne 0 ]; then
|
349
|
+
usage $(basename $0)
|
350
|
+
exit 1
|
351
|
+
fi
|
352
|
+
eval set -- "$options"
|
353
|
+
|
354
|
+
while true
|
355
|
+
do
|
356
|
+
case "$1" in
|
357
|
+
-h|--help) usage $0 && exit 0;;
|
358
|
+
-p|--path) path=$2; shift 2;;
|
359
|
+
-n|--name) name=$2; shift 2;;
|
360
|
+
-c|--clean) clean=$2; shift 2;;
|
361
|
+
-R|--release) release=$2; shift 2;;
|
362
|
+
-m|--releaseminor) releaseminor=$2; shift 2;;
|
363
|
+
--) shift 1; break ;;
|
364
|
+
*) break ;;
|
365
|
+
esac
|
366
|
+
done
|
367
|
+
|
368
|
+
if [ ! -z "$clean" -a -z "$path" ]; then
|
369
|
+
clean || exit 1
|
370
|
+
exit 0
|
371
|
+
fi
|
372
|
+
|
373
|
+
needed_pkgs=""
|
374
|
+
type yum >/dev/null 2>&1
|
375
|
+
if [ $? -ne 0 ]; then
|
376
|
+
needed_pkgs="yum $needed_pkgs"
|
377
|
+
fi
|
378
|
+
|
379
|
+
type curl >/dev/null 2>&1
|
380
|
+
if [ $? -ne 0 ]; then
|
381
|
+
needed_pkgs="curl $needed_pkgs"
|
382
|
+
fi
|
383
|
+
|
384
|
+
if [ -n "$needed_pkgs" ]; then
|
385
|
+
echo "Missing commands: $needed_pkgs"
|
386
|
+
echo "Please install these using \"sudo apt-get install $needed_pkgs\""
|
387
|
+
exit 1
|
388
|
+
fi
|
389
|
+
|
390
|
+
if [ -z "$path" ]; then
|
391
|
+
path=$default_path
|
392
|
+
fi
|
393
|
+
|
394
|
+
if [ -z "$release" ]; then
|
395
|
+
if [ "$is_centos" ]; then
|
396
|
+
release=$(cat /etc/centos-release |awk '/^Fedora/ {print $3}')
|
397
|
+
else
|
398
|
+
echo "This is not a centos host and release missing, defaulting to 6.3. use -R|--release to specify release"
|
399
|
+
release=6
|
400
|
+
fi
|
401
|
+
fi
|
402
|
+
|
403
|
+
if [ -z "$releaseminor" ]; then
|
404
|
+
releaseminor=3
|
405
|
+
fi
|
406
|
+
|
407
|
+
if [ "$(id -u)" != "0" ]; then
|
408
|
+
echo "This script should be run as 'root'"
|
409
|
+
exit 1
|
410
|
+
fi
|
411
|
+
|
412
|
+
|
413
|
+
rootfs_path=$path/rootfs
|
414
|
+
config_path=$default_path/$name
|
415
|
+
cache=$cache_base/$release
|
416
|
+
|
417
|
+
revert()
|
418
|
+
{
|
419
|
+
echo "Interrupted, so cleaning up"
|
420
|
+
lxc-destroy -n $name
|
421
|
+
# maybe was interrupted before copy config
|
422
|
+
rm -rf $path/$name
|
423
|
+
rm -rf $default_path/$name
|
424
|
+
echo "exiting..."
|
425
|
+
exit 1
|
426
|
+
}
|
427
|
+
|
428
|
+
trap revert SIGHUP SIGINT SIGTERM
|
429
|
+
|
430
|
+
copy_configuration
|
431
|
+
if [ $? -ne 0 ]; then
|
432
|
+
echo "failed write configuration file"
|
433
|
+
exit 1
|
434
|
+
fi
|
435
|
+
|
436
|
+
install_centos
|
437
|
+
if [ $? -ne 0 ]; then
|
438
|
+
echo "failed to install centos"
|
439
|
+
exit 1
|
440
|
+
fi
|
441
|
+
|
442
|
+
configure_centos
|
443
|
+
if [ $? -ne 0 ]; then
|
444
|
+
echo "failed to configure centos for a container"
|
445
|
+
exit 1
|
446
|
+
fi
|
447
|
+
|
448
|
+
|
449
|
+
if [ ! -z $clean ]; then
|
450
|
+
clean || exit 1
|
451
|
+
exit 0
|
452
|
+
fi
|
453
|
+
echo "container rootfs and config created"
|