source: ror-farm/ror-farm-add

Last change on this file was 693, checked in by lucas, 7 years ago

permission fixes

  • Property svn:executable set to *
File size: 10.8 KB
Line 
1#!/bin/bash
2
3# ror-farm-add (c) 2008, 2009, 2010 Bearstech - http://bearstech.com
4#
5# Depends: util-vserver vserver-debiantools lvm2 passwd pwgen
6# Recommends: mysql-client
7
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
21THIS_NAME=ror-farm-add
22THIS_VERSION=3
23
24# Distro-specific paths
25#
26VSERVER_CONF=/etc/vservers
27VSERVER_HOME=/var/lib/vservers
28
29# Default options
30#
31domain=ror.bearstech.com
32vgname=$(vgs --noheadings | awk '{ print $1 }' | head -1)
33slices=1
34template=template
35dbengine=mysql
36ssh_keys=""
37mail=""
38
39help() {
40  cat << EOF
41Usage: $THIS_NAME [options] vserver-name vserver-id
42
43Creates a new RoR-ready vserver instance.
44
45Options:
46  --domain       vserver template (default: '$domain')
47  --vgname       LVM volume group for vserver home (default: '$vgname')
48  --slices       Number of slices to allocate for this rorette (CPU/RAM/Disk)
49                 can be 1, 2 or 4 (default: $slices)
50  --template     vserver filesystem template (default: '$template')
51  --dbengine     database engine (default: '$dbengine')
52  --ssh-key      install a SSH public key file in the ror account (no default value)
53                 (can be specified several times)
54  --mail         E-mail address to be used as MAILTO for cron
55  --help, -h     this help
56  --version, -v  this script version
57EOF
58}
59
60version() {
61  echo "$THIS_NAME $THIS_VERSION"
62}
63
64error() {
65  echo "$THIS_NAME: error: $*"
66  exit 1
67}
68
69lv_from_slices() {
70  if [ $slices -eq 1 ]; then
71    lvsize=1G
72  elif [ $slices -eq 2 ]; then
73    lvsize=2G
74  elif [ $slices -eq 4 ]; then
75    lvsize=4G
76  else
77    echo "$THIS_NAME: error, slice must be a valid number (was: '$slices')"
78    exit 1
79  fi
80}
81
82ram_from_slices() {
83  if [ $slices -eq 1 ]; then
84    ram='512 384'
85  elif [ $slices -eq 2 ]; then
86    ram='1024 768'
87  elif [ $slices -eq 4 ]; then
88    ram='2048 1536'
89  else
90    echo "$THIS_NAME: error, slice must be a valid number (was: '$slices')"
91    exit 1
92  fi
93}
94
95# non-linear progression
96cpu_from_slices() {
97  if [ $slices -eq 1 ]; then
98    cpu='64 1536'
99  elif [ $slices -eq 2 ]; then
100    cpu='96 2048'
101  elif [ $slices -eq 4 ]; then
102    cpu='148 2694'
103  else
104    echo "$THIS_NAME: error, slice must be a valid number (was: '$slices')"
105    exit 1
106  fi
107}
108
109# Parse args
110#
111parse_opt=run
112while [ $parse_opt != "done"  ] ; do
113  case "$1" in
114
115    --domain)      shift; domain="$1"; shift;;
116    --vgname)      shift; vgname="$1"; shift;;
117    --slices)      shift; slices="$1"; shift;;
118    --template)    shift; template="$1"; shift;;
119    --dbengine)    shift; dbengine="$1"; shift;;
120    --mail)        shift; mail="$1"; shift;;
121    --ssh-key)     shift; ssh_keys="$ssh_keys
122$1"; shift;;
123
124    --help|-h)     shift; help; exit 0;;
125    --version|-v)  shift; version; exit 0;;
126
127    --)            shift; parse_opt=done;;
128    -*)            echo "$THIS_NAME: unknown option '$1'"; exit 1;;
129    *)             parse_opt=done;;
130  esac
131done
132name="$1"; shift
133id="$1"; shift
134
135
136# Sanity checks (lots of them)
137#
138
139set -e
140
141if [ -z "$name" ]; then
142  error "missing vserver-name"
143fi
144if [ x"$name" != x`echo "$name" | sed -ne '/^[a-z][a-z0-9]\{1,9\}$/p'` ]; then
145  error "unsupported vserver-name '$name' (0-9, a-z, 10 chars max, begins with a letter)"
146fi
147if [ -d "$VSERVER_CONF/$name" ]; then
148  error "vserver '$name' already exists"
149fi
150
151if [ -z "$id" ]; then
152  error "missing vserver-id"
153fi
154if [ $id -lt 2 -o $id -gt 49151 ]; then
155  error "vserver-id must be in 2..49151 range"
156fi
157cd $VSERVER_CONF
158for c in */context; do
159  [ ! -f "$c" ] && continue
160  if [ "$id" = `cat $c` ]; then
161    error "vserver-id already used by '${c/\/context/}'"
162  fi
163done
164
165if [ -z "$domain" ]; then
166  error "empty domain unsupported, use a dummy"
167fi
168
169if [ -z "$vgname" ]; then
170  error "missing --vgname"
171fi
172vgs "$vgname" >/dev/null 2>/dev/null || \
173  error "volume group '$vgname' not found"
174
175if [ -z "$slices" ]; then
176  error "missing --slices"
177fi
178if [ x"$slices" != x`echo "$slices" | sed -ne '/^[124]$/p'` ]; then
179  error "unsupported slices amount '$slices' (use 1, 2 or 4)"
180fi
181
182if [ -z "$template" ]; then
183  error "missing --template"
184fi
185if [ x`echo "$template" | sed -ne '/\//p'` != x ]; then
186  error "unsane template name ('$template')"
187fi
188if [ ! -d "$VSERVER_HOME/$template" ]; then
189  error "filesystem template '$template' not found (in $VSERVER_HOME)"
190fi
191
192# From slices to sizes
193lv_from_slices
194
195ram_from_slices
196ram_rss=$(echo $ram | cut -d' ' -f 1)
197ram_anon=$(echo $ram | cut -d' ' -f 2)
198
199cpu_from_slices
200cpu_nproc=$(echo $cpu | cut -d' ' -f 1)
201cpu_openfd=$(echo $cpu | cut -d' ' -f 2)
202
203
204# Setup vserver config
205#
206mkdir $VSERVER_CONF/$name
207cd    $VSERVER_CONF/$name
208
209mkdir -p apps/init
210mkdir -p apps/pkgmgmt
211mkdir -p cpuset
212mkdir -p interfaces/0
213mkdir -p rlimits
214mkdir -p uts
215
216ln -s $VSERVER_CONF/.defaults/run/$name      run
217ln -s $VSERVER_CONF/.defaults/vdirbase/$name vdir
218
219echo default > apps/init/mark
220echo $id     > context
221echo $name   > name
222echo $name   > uts/nodename
223cat <<EOF    > fstab
224none    /proc           proc    defaults                0 0
225none    /tmp            tmpfs   size=16m,mode=1777      0 0
226none    /dev/pts        devpts  gid=5,mode=620          0 0
227EOF
228
229# Rationale for the id -> ip mapping:
230# - id starts with 2, IP starts with 10.0.0.2 (.1 is gateway)
231# - map 250 ids per /24, we thus have 4 free IPs per /24 if needed
232# - id 2..251 map directly to 10.0.0.id
233#
234ip=10.0.$((($id-2) / 250)).$((2 + ($id-2) % 250))
235echo dummy0       > interfaces/0/dev
236echo $ip          > interfaces/0/ip
237echo 16           > interfaces/0/prefix
238
239mb=$((1024*1024 / `getconf PAGE_SIZE`))
240echo $(($ram_rss*$mb))  > rlimits/rss
241echo $(($ram_anon*$mb)) > rlimits/anon
242echo $cpu_nproc         > rlimits/nproc
243echo $cpu_openfd        > rlimits/nofile
244echo $cpu_openfd        > rlimits/openfd
245echo $cpu_nproc         > rlimits/nsock
246# upgrade /tmp size in > fstab ? (default: 16MB)
247# Display memory limits within a vserver (see http://linux-vserver.org/Memory_Limits)
248echo "VIRT_MEM"   >> flags
249
250
251# Setup vserver's filesystem root
252#
253cd $VSERVER_HOME
254mkdir $name
255
256# Create this vserver's home
257#
258lvcreate --quiet -L $lvsize -n $name $vgname >/dev/null
259mke2fs -q -i 4069 -j -m 0 /dev/$vgname/$name
260
261# Setup permnanent mountpoints, and mount them
262#
263cat <<EOF >>/etc/fstab
264$VSERVER_HOME/$template  $VSERVER_HOME/$name  bind  ro,bind  0  0
265/dev/$vgname/$name  $VSERVER_HOME/$name/home  ext3  defaults,noatime  0  0
266EOF
267mount $name
268mount $name/home
269
270
271# Populate home with a template copy
272#
273cp -a $template/home/* $name/home
274
275
276# Fixup various files to customize the template filesystem
277# (the following files are symlinked from /etc/ to /home/etc)
278#
279cd $VSERVER_HOME/$name
280
281cat  <<EOF         > etc/hosts
282127.0.0.1       localhost.localdomain localhost
283$ip     $name.$domain $name
284EOF
285echo $name          > etc/hostname
286echo $name.$domain  > etc/mailname
287rm -f etc/motd
288cat <<EOF           > etc/motd
289
290Welcome to $name.$domain, your own RoR server.
291
292See http://my.$domain/projects/show/$id for your account
293settings and monitoring. Have fun ! The Bearstech RoR team.
294
295EOF
296
297# Adjust cronjob times (mitigate 'cron storm' across many vservers)
298#
299delta=$(($id % 20))
300cron_tmp=`mktemp -t crontab.XXXXXXXX`
301cron_daily=$((10 + $delta - 1))
302cron_weekly=$((30 + $delta - 1))
303cron_monthly=$((40 + $delta - 1))
304sed \
305  -e 's/^[0-9]\+ \(.*cron\.daily.*\)/'$cron_daily' \1/' \
306  -e 's/^[0-9]\+ \(.*cron\.weekly.*\)/'$cron_weekly' \1/' \
307  -e 's/^[0-9]\+ \(.*cron\.monthly.*\)/'$cron_monthly' \1/' \
308  < etc/crontab \
309  > $cron_tmp
310mv $cron_tmp etc/crontab
311
312# Cleanup /var (yes, we remove *all* files)
313#
314find $VSERVER_HOME/$name/var/ -type f -exec rm {} \;
315touch $VSERVER_HOME/$name/var/lib/dpkg/status  # make cron.daily/standard happy (bug #26)
316
317# Deploy cron template
318if [ ! -z "$mail" ]; then
319  cd $VSERVER_HOME/$name/var/spool/cron/crontabs
320  cat <<EOF > ror
321#
322#
323#
324# Do not remove the following line unless you don't want to hear about
325# your rorette's problems
326MAILTO=$mail
327
328# m h  dom mon dow   command
329
330EOF
331  chown ror:ror ror
332fi
333
334
335# Cleanup user account
336#
337cd $VSERVER_HOME/$name/home/ror
338
339rm -rf .aptitude
340rm -f .bash_history .lesshst .viminfo
341rm -f .ssh/known_hosts .ssh/id_*
342rm -f gem/source_cache
343rm -f gem/cache/*
344rm -rf rubygems-*
345rm -f http/tmp/*
346rm -f http/log/*
347
348
349# Shell account (created on root-server, redirects to ror@$name)
350#
351useradd \
352  --uid 0 --gid 0 --non-unique \
353  --password '*' \
354  --comment "by=ror-farm-add,name=$name,id=$id" \
355  --home  $VSERVER_HOME/$name/home/ror \
356  --shell /usr/local/bin/ror-farm-shell \
357  $name
358
359
360# Databases (a common password for all of them)
361#
362db_pass=`pwgen 8 1`
363
364if [ $dbengine = "mysql" ]; then
365   
366    # Setup MySQL accounts and databases
367    #
368   
369    # find where the master is
370    sqlmaster=$(grep "sql-master" /etc/ror-farm/cloud | awk '{print $2}')
371   
372    if mysql --version >/dev/null 2>/dev/null; then
373        cat <<EOF | ssh root@${sqlmaster} mysql
374CREATE DATABASE \`${name}_dev\` CHARSET utf8;
375CREATE DATABASE \`${name}_prod\` CHARSET utf8;
376GRANT ALL PRIVILEGES ON \`${name}\_dev\`.* TO '$name'@'%';
377GRANT ALL PRIVILEGES ON \`${name}\_prod\`.* TO '$name'@'%';
378SET PASSWORD FOR '$name'@'%'=PASSWORD('$db_pass');
379FLUSH PRIVILEGES;
380EOF
381       
382        cat <<EOF > .my.cnf
383[client]
384host = 10.0.0.1
385user = $name
386pass = $db_pass
387default-character-set = utf8
388EOF
389
390        chmod 600 .my.cnf
391        chown ror:ror .my.cnf
392    fi
393
394fi
395
396
397if [ $dbengine = "postgresql" ]; then
398    # Setup PostgreSQL accounts and databases
399    #
400   
401    # find where the master is
402    sqlmaster=$(grep "sql-master" /etc/ror-farm/cloud | awk '{print $2}')
403   
404    if ssh postgres@$sqlmaster "psql --version >/dev/null 2>/dev/null"; then
405        ssh postgres@${sqlmaster} createuser -U postgres -D -R -S \"$name\"
406        ssh postgres@${sqlmaster} createdb \"${name}_prod\" -O \"$name\"
407        ssh postgres@${sqlmaster} psql -d \"${name}_prod\" -c \"alter user $name with password \'$db_pass\'\"
408       
409        cat <<EOF > .pgpass
41010.0.0.1:5432:${name}_prod:$name:$db_pass
411EOF
412        chmod 600 .pgpass
413        chown ror:ror .pgpass
414       
415        cat <<EOF >> .bashrc
416
417export PGHOST=10.0.0.1
418export PGPORT=5432
419export PGDATABASE=${name}_prod
420export PGUSER=$name
421
422EOF
423
424    fi
425fi
426
427# Setup SSH access if asked for
428if [ ! -z "$ssh_keys" ]; then
429  for k in $ssh_keys; do
430    cat $k >> .ssh/authorized_keys
431  done
432  # be sure to chown the file, SSH is picky
433  chown ror:ror .ssh/authorized_keys
434fi
435
436# Setup PostgreSQL accounts and databases
437#
438#if psql --version >/dev/null 2>/dev/null; then
439#fi
440
441
442# All done, start new vserver
443#
444vserver "$name" start
Note: See TracBrowser for help on using the repository browser.