To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / deploy @ 1597:eeacb8332051

1 1595:98384d0defa0 Chris
2
Deploying the SoundSoftware site
3
4 1597:eeacb8332051 Chris
5
6
After deployment
7
----------------
8
9
There is a smoke test script at test/smoketest.sh which checks that
10
the home page, a project page, a repo page etc can be retrieved. Some
11
of the pages it tries to retrieve are dependent on their generating
12
cron scripts having run at least once since the server was set up.
13
14 1593:83412a0a2389 Chris
#!/bin/bash
15
16
# To be sourced into a container-specific start.sh file, not run
17
# standalone
18
19
usage() {
20
    echo "Usage: $0 <database-password> <api-key> <api-httpauth-password>" 1>&2
21
    exit 2
22
}
23
24
dbpass="$1"
25
if [ -z "$dbpass" ]; then
26
    usage
27
fi
28
29
apikey="$2"
30
if [ -z "$apikey" ]; then
31
    usage
32
fi
33
34
apipass="$3"
35
if [ -z "$apipass" ]; then
36
    usage
37
fi
38
39
set -eu -o pipefail
40
41
rootdir="$mydir/../.."
42
43
deploydir="$rootdir"/deploy
44
if [ ! -d "$deploydir" ]; then
45
    echo "ERROR: Unexpected repository layout - expected directory at $deploydir"
46
    exit 2
47
fi
48
49
managerdir="$deploydir/vagrant"
50
if [ ! -d "$managerdir" ]; then
51
    echo "ERROR: Required directory $managerdir not found"
52
    exit 2
53
fi
54
55
configdir="$deploydir/config"
56
if [ ! -d "$configdir" ]; then
57
    echo "ERROR: Required directory $configdir not found"
58
    exit 2
59
fi
60
61
if [ ! -f "$rootdir/postgres-dumpall" ]; then
62
    echo "ERROR: I expect to find a Postgres SQL multi-db dump file in $rootdir/postgres-dumpall"
63
    exit 2
64
fi
65
66
fontdir="$rootdir"/public/themes/soundsoftware/stylesheets/fonts
67
if [ ! -f "$fontdir/24BC0E_0_0.woff" ]; then
68
    echo "ERROR: I expect to find necessary webfonts in $fontdir"
69
    exit 2
70
fi
71
72
apischeme=http
73
apihost=localhost
74
75
#apischeme=https
76
#apihost=code.soundsoftware.ac.uk
77
78
for f in "$configdir"/*.in "$rootdir"/extra/soundsoftware/extract-docs.sh ; do
79
    out="$configdir"/$(basename "$f" .in).gen
80
    cat "$f" | sed \
81
                   -e 's/INSERT_DATABASE_PASSWORD_HERE/'"$dbpass"'/g' \
82
                   -e 's/INSERT_API_KEY_HERE/'"$apikey"'/g' \
83
                   -e 's/INSERT_API_SCHEME_HERE/'"$apischeme"'/g' \
84
                   -e 's/INSERT_API_HOST_HERE/'"$apihost"'/g' \
85
                   -e 's/INSERT_API_USER_HERE/user/g' \
86
                   -e 's/INSERT_API_PASSWORD_HERE/'"$apipass"'/g' \
87
                   > "$out"
88
done
89 1570:ae2f71010562 Chris
90
# A test Apache config. Lacks SSL, lacks a desirable extra layer of
91
# authentication for admin interface paths. Do not deploy this.
92
93 1593:83412a0a2389 Chris
# Note this has been updated for Apache 2.4, which introduced a number
94
# of (welcome) changes to access control directives.
95
96 1570:ae2f71010562 Chris
PerlLoadModule Apache::Authn::SoundSoftware
97
98
<VirtualHost *:80>
99
        ServerName code.soundsoftware.ac.uk
100
        ServerAdmin chris.cannam@soundsoftware.ac.uk
101
102
        DocumentRoot /var/www/code/public
103
        PassengerRestartDir restart_files
104
        PassengerHighPerformance on
105
        PassengerMaxRequests 50000
106
        PassengerStatThrottleRate 5
107
	PassengerStartTimeout 60
108 1571:4c2b25b7e85f Chris
	PassengerFriendlyErrorPages on
109 1570:ae2f71010562 Chris
        RailsSpawnMethod smart
110
        ExpiresDefault "access plus 1 minute"
111
112 1590:c18460da6620 Chris
#        <Location /sys>
113
#		AuthType Basic
114
#		AuthUserFile "/etc/apache2/auth/user.htpasswd"
115
#		AuthName "code.soundsoftware.ac.uk"
116
#		Require user user
117
#	</Location>
118
119
#	<Location /admin>
120
#		AuthType Digest
121
#		AuthUserFile "/etc/apache2/auth/admin.htdigest"
122
#		AuthName "code.soundsoftware.ac.uk admin interface"
123
#		Require user admin
124
#	</Location>
125
126 1570:ae2f71010562 Chris
        <DirectoryMatch "^/.*/\.svn/">
127 1593:83412a0a2389 Chris
                Require all denied
128 1570:ae2f71010562 Chris
        </DirectoryMatch>
129
130
        <DirectoryMatch "^/.*/\.hg/">
131 1593:83412a0a2389 Chris
                Require all denied
132 1570:ae2f71010562 Chris
        </DirectoryMatch>
133
134
        <DirectoryMatch "^/.*/\.git/">
135 1593:83412a0a2389 Chris
                Require all denied
136 1570:ae2f71010562 Chris
        </DirectoryMatch>
137
138
        <Directory /var/www/code/public>
139
                Options -MultiViews
140
	</Directory>
141
142
        <Directory /var/www/code/public/themes/soundsoftware/stylesheets/fonts>
143
		# Avoid other sites embedding our fonts
144
		RewriteEngine on
145
		RewriteCond %{HTTP_REFERER} !^$
146
		RewriteCond %{HTTP_REFERER} !^http(s)?://code.soundsoftware.ac.uk/.*$ [NC]
147
		RewriteRule \.(ttf|woff|eot|otf|svg|zip|gz|html|txt)$ - [F]
148
	</Directory>
149
150
	ScriptAlias /hg "/var/hg/index.cgi"
151
152
	<Location /hg>
153
               	AuthName "Mercurial"
154
                AuthType Basic
155
                Require valid-user
156
		PerlAccessHandler Apache::Authn::SoundSoftware::access_handler
157
      		PerlAuthenHandler Apache::Authn::SoundSoftware::authen_handler
158
		PerlSetVar HTTPS "on"
159
		SoundSoftwareDSN "dbi:Pg:database=code;host=localhost"
160
    		SoundSoftwareDbUser "code"
161 1593:83412a0a2389 Chris
     		SoundSoftwareDbPass "INSERT_DATABASE_PASSWORD_HERE"
162 1570:ae2f71010562 Chris
		SoundSoftwareRepoPrefix "/var/hg/"
163 1576:d1de6986e429 Chris
                #!!! "on" in production please!:
164
                SoundSoftwareSslRequired "off"
165 1570:ae2f71010562 Chris
		Options +ExecCGI
166
		AddHandler cgi-script .cgi
167
		ExpiresDefault now
168
        </Location>
169
170
	Alias /git "/var/files/git-mirror"
171
172
	<Directory "/var/files/git-mirror">
173
		Options -Indexes +FollowSymLinks
174 1593:83412a0a2389 Chris
                Require all granted
175 1570:ae2f71010562 Chris
	</Directory>
176
	<Directory ~ "/var/files/git-mirror/.*\.workdir">
177 1593:83412a0a2389 Chris
                Require all denied
178 1570:ae2f71010562 Chris
	</Directory>
179
	<Directory ~ "/var/files/git-mirror/__.*">
180 1593:83412a0a2389 Chris
                Require all denied
181 1570:ae2f71010562 Chris
	</Directory>
182
183
	ErrorLog /var/log/apache2/code-error.log
184
	CustomLog /var/log/apache2/code-access.log vhost_combined
185
186
        LogLevel warn
187
        ServerSignature Off
188
189
</VirtualHost>
190
191 1586:d0d59d12db94 Chris
#!/bin/sh
192 1590:c18460da6620 Chris
193 1586:d0d59d12db94 Chris
outfile="/var/files/backups/postgres-dumpall-`date +%Y%m%d%H%M`"
194 1590:c18460da6620 Chris
195 1586:d0d59d12db94 Chris
oldmask=`umask`
196
umask 0277
197 1590:c18460da6620 Chris
198 1586:d0d59d12db94 Chris
su postgres -c /usr/bin/pg_dumpall > "$outfile" && bzip2 "$outfile"
199 1590:c18460da6620 Chris
200 1586:d0d59d12db94 Chris
umask "$oldmask"
201
#!/bin/bash
202 1590:c18460da6620 Chris
203 1586:d0d59d12db94 Chris
cd /tmp
204 1590:c18460da6620 Chris
205 1586:d0d59d12db94 Chris
/var/www/code/docgen/extract-docs.sh
206 1590:c18460da6620 Chris
207 1586:d0d59d12db94 Chris
#!/bin/bash
208 1590:c18460da6620 Chris
209 1586:d0d59d12db94 Chris
sudo -u code sh -c "cd /var/www/code ; ./script/rails runner -e production extra/soundsoftware/get-statistics.rb >> log/statistics.log"
210 1590:c18460da6620 Chris
211 1586:d0d59d12db94 Chris
#!/bin/bash
212 1590:c18460da6620 Chris
213 1586:d0d59d12db94 Chris
tail -2 /var/log/external-repos.log
214
#!/bin/bash
215
216 1590:c18460da6620 Chris
## No longer used - this site is now static
217
218
# /usr/bin/wget -O - -q -t 1 http://www.soundsoftware.ac.uk/cron.php
219
220 1586:d0d59d12db94 Chris
#!/bin/bash
221 1590:c18460da6620 Chris
222 1586:d0d59d12db94 Chris
sudo -u code sh -c "cd /var/www/code ; ./script/rails runner \"Repository.fetch_changesets\" -e production 2>&1 | grep -v 'Not trusting' | grep -v 'svn:' | grep -v 'working copy' | grep -v 'deprecated' | grep -v 'version_requirements'"
223
exit 0
224 1590:c18460da6620 Chris
225 1586:d0d59d12db94 Chris
#!/bin/bash
226 1590:c18460da6620 Chris
227 1586:d0d59d12db94 Chris
sudo -H -u www-data /var/www/code/reposman/run-external.sh
228 1590:c18460da6620 Chris
229 1586:d0d59d12db94 Chris
#!/bin/sh
230 1590:c18460da6620 Chris
231 1586:d0d59d12db94 Chris
rm -f /var/www/code/tmp/cache/*/*/views*explore*
232
#!/bin/bash
233 1590:c18460da6620 Chris
234 1586:d0d59d12db94 Chris
logfile="/var/www/code/log/export-git.log"
235 1590:c18460da6620 Chris
236 1586:d0d59d12db94 Chris
sudo -u code sh -c "cd /tmp ; /var/www/code/extra/soundsoftware/export-git.sh production /var/hg /var/files/git-mirror >> $logfile 2>&1"
237 1590:c18460da6620 Chris
238 1586:d0d59d12db94 Chris
#!/bin/bash
239 1590:c18460da6620 Chris
240 1586:d0d59d12db94 Chris
sudo -u www-data /var/www/code/reposman/run-reposman.sh
241
242
#!/bin/sh
243 1596:45b0571b684d Chris
cd /
244 1586:d0d59d12db94 Chris
for location in var/www etc/apache2 etc/cron.*; do
245
	target="/var/files/backups/`echo $location | sed 's,/,_,g'`-`date +%Y%m%d%H%M`"
246
	oldmask=`umask`
247
	umask 0277
248
	tar cjf "$target".tar.bz2 "$location"
249
	umask "$oldmask"
250
done
251
252 1570:ae2f71010562 Chris
production:
253
  adapter: postgresql
254
  database: code
255
  host: localhost
256
  username: code
257 1593:83412a0a2389 Chris
  password: "INSERT_DATABASE_PASSWORD_HERE"
258 1570:ae2f71010562 Chris
259 1576:d1de6986e429 Chris
[paths]
260
/ = /var/hg/*
261
262
[web]
263
allow_archive = gz, zip, bz2
264
allow_push = *
265
#!/usr/bin/env python
266
#
267
# An example CGI script to export multiple hgweb repos, edit as necessary
268
269
# adjust python path if not a system-wide install:
270
#import sys
271
#sys.path.insert(0, "/path/to/python/lib")
272
273
# enable importing on demand to reduce startup time
274
from mercurial import demandimport; demandimport.enable()
275
276
# Uncomment to send python tracebacks to the browser if an error occurs:
277
import cgitb
278
cgitb.enable()
279
280
# If you'd like to serve pages with UTF-8 instead of your default
281
# locale charset, you can do so by uncommenting the following lines.
282
# Note that this will cause your .hgrc files to be interpreted in
283
# UTF-8 and all your repo files to be displayed using UTF-8.
284
#
285
import os
286
os.environ["HGENCODING"] = "UTF-8"
287
288
from mercurial.hgweb.hgwebdir_mod import hgwebdir
289
import mercurial.hgweb.wsgicgi as wsgicgi
290
291
# The config file looks like this.  You can have paths to individual
292
# repos, collections of repos in a directory tree, or both.
293
#
294
# [paths]
295
# virtual/path1 = /real/path1
296
# virtual/path2 = /real/path2
297
# virtual/root = /real/root/*
298
# / = /real/root2/*
299
# virtual/root2 = /real/root2/**
300
#
301
# [collections]
302
# /prefix/to/strip/off = /root/of/tree/full/of/repos
303
#
304
# paths example:
305
#
306
# * First two lines mount one repository into one virtual path, like
307
# '/real/path1' into 'virtual/path1'.
308
#
309
# * The third entry mounts every mercurial repository found in '/real/root'
310
# in 'virtual/root'. This format is preferred over the [collections] one,
311
# since using absolute paths as configuration keys is not supported on every
312
# platform (especially on Windows).
313
#
314
# * The fourth entry is a special case mounting all repositories in
315
# /'real/root2' in the root of the virtual directory.
316
#
317
# * The fifth entry recursively finds all repositories under the real root,
318
# and mounts them using their relative path (to given real root) under the
319
# virtual root.
320
#
321
# collections example: say directory tree /foo contains repos /foo/bar,
322
# /foo/quux/baz.  Give this config section:
323
#   [collections]
324
#   /foo = /foo
325
# Then repos will list as bar and quux/baz.
326
#
327
# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples
328
# or use a dictionary with entries like 'virtual/path': '/real/path'
329
330
application = hgwebdir('hgweb.config')
331
wsgicgi.launch(application)
332 1586:d0d59d12db94 Chris
# see "man logrotate" for details
333
# rotate log files weekly
334
weekly
335
336 1590:c18460da6620 Chris
# use the syslog group by default, since this is the owning group
337
# of /var/log/syslog.
338
su root syslog
339
340 1586:d0d59d12db94 Chris
# keep 4 weeks worth of backlogs
341
rotate 4
342
343
# create new (empty) log files after rotating old ones
344
create
345
346
# uncomment this if you want your log files compressed
347
#compress
348
349
# packages drop log rotation information into this directory
350
include /etc/logrotate.d
351
352
# no packages own wtmp, or btmp -- we'll rotate them here
353
/var/log/wtmp {
354
    missingok
355
    monthly
356
    create 0664 root utmp
357
    rotate 1
358
}
359
360
/var/log/btmp {
361
    missingok
362
    monthly
363
    create 0660 root utmp
364
    rotate 1
365
}
366
367
# system-specific logs may be configured here
368
/var/www/code/log/*.log {
369
	weekly
370
	missingok
371
	rotate 52
372
	compress
373
	delaycompress
374
	create 640 code code
375
	sharedscripts
376
	postrotate
377
		touch /var/www/code/restart_files/restart.txt
378
	endscript
379
}
380
381
/var/log/reposman.log {
382
        weekly
383
        missingok
384
        rotate 52
385
        compress
386
        delaycompress
387
        create 640 www-data code
388
        sharedscripts
389
}
390
391
/var/log/external-repos.log {
392
        weekly
393
        missingok
394
        rotate 52
395
        compress
396
        delaycompress
397
        create 640 www-data code
398
        sharedscripts
399
}
400
401 1571:4c2b25b7e85f Chris
PassengerMaxPoolSize 60
402
403
LoadModule passenger_module /var/lib/gems/2.3.0/gems/passenger-4.0.60/buildout/apache2/mod_passenger.so
404
PassengerRoot /var/lib/gems/2.3.0/gems/passenger-4.0.60
405
PassengerDefaultRuby /usr/bin/ruby2.3
406
# Apache::DBI is supposed to be a transparent replacement for Perl DBI with
407
# better performance when multiple connections are made with common DSN, user
408
# and password
409
PerlModule Apache::DBI
410 1590:c18460da6620 Chris
#!/bin/bash
411
logfile=/var/log/external-repos.log
412
(
413
flock -s 200
414
echo >> $logfile
415
date >> $logfile
416
/var/www/code/reposman/convert-external-repos.rb \
417
	-s /var/hg \
418 1593:83412a0a2389 Chris
	-r INSERT_API_SCHEME_HERE://INSERT_API_HOST_HERE/ \
419 1590:c18460da6620 Chris
	-k INSERT_API_KEY_HERE \
420
	-v \
421 1593:83412a0a2389 Chris
	--http-user=INSERT_API_USER_HERE \
422
	--http-pass=INSERT_API_PASSWORD_HERE \
423 1590:c18460da6620 Chris
        -c "/var/www/code/reposman/update-external-repo.sh" \
424
	>> $logfile 2>&1
425
date >> $logfile
426
echo Done >> $logfile
427
)200>>$logfile
428
#!/bin/bash
429
logfile=/var/log/reposman.log
430
(
431
flock -s 200
432
echo >> $logfile
433
/var/www/code/reposman/reposman-soundsoftware.rb \
434
	-s /var/hg \
435 1593:83412a0a2389 Chris
	-r INSERT_API_SCHEME_HERE://INSERT_API_HOST_HERE/ \
436 1590:c18460da6620 Chris
	-k INSERT_API_KEY_HERE \
437 1593:83412a0a2389 Chris
	--http-user=INSERT_API_USER_HERE \
438
	--http-pass=INSERT_API_PASSWORD_HERE \
439 1590:c18460da6620 Chris
	-o www-data \
440
	-g code \
441
	-c "/var/www/code/reposman/run-hginit.sh" \
442
	--scm=Mercurial \
443
	>> $logfile 2>&1
444
)200>>$logfile
445 1587:d8949733849d Chris
446
FROM ubuntu:16.04
447
MAINTAINER Chris Cannam <cannam@all-day-breakfast.com>
448
449
COPY . /var/www/code
450
451
WORKDIR /var/www/code
452
453
INSERT_PROVISIONING_HERE
454
455
# Start Postgres and foregrounded Apache
456
457
RUN echo "#!/bin/bash"                      > container-run.sh
458
RUN echo "/etc/init.d/postgresql start"    >> container-run.sh
459
RUN echo "apache2ctl -D FOREGROUND"        >> container-run.sh
460
RUN chmod +x container-run.sh
461
462
EXPOSE 80
463
CMD ./container-run.sh
464
465
466
# For documentation and experimental purposes only. As a
467
# reconstruction of the machine image that runs this application,
468
# there are lots of things missing here; but as a good Docker
469
# configuration, it fails by mixing together rather a lot of concerns.
470
471
FROM ubuntu:16.04
472
MAINTAINER Chris Cannam <cannam@all-day-breakfast.com>
473
474
RUN apt-get update && \
475
    apt-get install -y \
476
    apache2 \
477
    apache2-dev \
478
    apt-utils \
479
    build-essential \
480
    cron \
481
    curl \
482
    doxygen \
483
    exim4 \
484
    git \
485
    graphviz \
486
    imagemagick \
487
    libapache-dbi-perl \
488
    libapache2-mod-perl2 \
489
    libapr1-dev \
490
    libaprutil1-dev \
491
    libauthen-simple-ldap-perl \
492
    libcurl4-openssl-dev \
493
    libdbd-pg-perl \
494
    libpq-dev \
495
    libmagickwand-dev \
496
    libio-socket-ssl-perl \
497
    logrotate \
498
    mercurial \
499
    postgresql \
500
    rsync \
501
    ruby \
502
    ruby-dev \
503
    sudo
504
505
# Also used on the live site, for javadoc extraction, but this is
506
# would be by far the biggest package here: let's omit it while we're
507
# not making use of it
508
#   openjdk-9-jdk-headless
509
510
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
511
512
513
# Passenger gets installed through gem, not apt
514
515
RUN gem install passenger -v 4.0.60 --no-rdoc --no-ri
516
RUN passenger-install-apache2-module --languages=ruby
517
518
519
# Copy across webapp, set up ownership
520
521
COPY . /var/www/code
522
523
RUN groupadd code
524
RUN useradd -g code -G www-data code
525
RUN chown -R code.www-data /var/www/code
526
RUN find /var/www/code -type d -exec chmod g+s \{\} \;
527
528
529
# Initialise /var/hg (in reality this would be mounted from somewhere)
530
531
RUN mkdir -p /var/hg
532
RUN chown code.www-data /var/hg
533
RUN chmod g+s /var/hg
534
COPY extra/soundsoftware/scripted-deploy/config/index.cgi /var/hg/
535
COPY extra/soundsoftware/scripted-deploy/config/hgweb.config /var/hg/
536
RUN chmod +x /var/hg/index.cgi
537
538
539
# We're based in the code webapp directory from here on
540
541
WORKDIR /var/www/code
542
543
544
# Set up database config etc
545
546
RUN cp extra/soundsoftware/scripted-deploy/config/database.yml.interpolated config/database.yml
547
548
549
# Install Rails and dependencies (database.yml must be populated before this)
550
551
RUN gem install bundler
552
RUN bundle install
553
554
555
# Initialise Redmine token (bundler must be installed before this)
556
557
RUN bundle exec rake generate_secret_token
558
559
560
# Import Postgres database from postgres-dumpall file
561
562
RUN chown postgres postgres-dumpall
563
RUN /etc/init.d/postgresql start && sudo -u postgres psql -f postgres-dumpall postgres
564
RUN rm postgres-dumpall
565
566
567
# Install Perl auth module for Hg access
568
569
RUN mkdir -p /usr/local/lib/site_perl/Apache/Authn/
570
RUN cp extra/soundsoftware/SoundSoftware.pm /usr/local/lib/site_perl/Apache/Authn/
571
572
573
# Set up Apache config (todo: insert variables)
574
575
RUN rm -f /etc/apache2/sites-enabled/000-default.conf
576
577
RUN cp extra/soundsoftware/scripted-deploy/config/passenger.conf /etc/apache2/mods-available/
578
RUN cp extra/soundsoftware/scripted-deploy/config/passenger.load /etc/apache2/mods-available/
579
RUN cp extra/soundsoftware/scripted-deploy/config/perl.conf      /etc/apache2/mods-available/
580
581
RUN ln -s ../mods-available/passenger.conf  /etc/apache2/mods-enabled/
582
RUN ln -s ../mods-available/passenger.load  /etc/apache2/mods-enabled/
583
RUN ln -s ../mods-available/perl.conf       /etc/apache2/mods-enabled/
584
RUN ln -s ../mods-available/expires.load    /etc/apache2/mods-enabled/
585
RUN ln -s ../mods-available/rewrite.load    /etc/apache2/mods-enabled/
586
RUN ln -s ../mods-available/cgi.load        /etc/apache2/mods-enabled/
587
588
RUN cp extra/soundsoftware/scripted-deploy/config/code.conf.interpolated /etc/apache2/sites-available/code.conf
589
RUN ln -s ../sites-available/code.conf /etc/apache2/sites-enabled/10-code.conf
590
591
RUN apache2ctl configtest
592
593
594
# Start Postgres and foregrounded Apache
595
596
RUN echo "#!/bin/bash"                      > container-run.sh
597
RUN echo "/etc/init.d/postgresql start"    >> container-run.sh
598
RUN echo "apache2ctl -D FOREGROUND"        >> container-run.sh
599
RUN chmod +x container-run.sh
600
601
EXPOSE 80
602
CMD ./container-run.sh
603
604 1569:26a4f99ec679 Chris
#!/bin/bash
605
606 1586:d0d59d12db94 Chris
mydir=$(dirname "$0")
607 1593:83412a0a2389 Chris
. "$mydir"/../any/prepare.sh
608 1574:7b23adecd963 Chris
609 1587:d8949733849d Chris
provisioning_commands=$(
610 1590:c18460da6620 Chris
    for x in "$deploydir"/provision.d/[0-9]*.sh; do
611 1587:d8949733849d Chris
        echo "RUN /bin/bash /var/www/code/deploy/provision.d/$(basename $x)"
612
    done | sed 's/$/\\n/' | fmt -2000 | sed 's/ RUN/RUN/g' )
613
614
( echo
615
  echo "### DO NOT EDIT THIS FILE - it is generated from Dockerfile.in"
616
  echo
617
) > "$managerdir/Dockerfile"
618
619
cat "$managerdir/Dockerfile.in" |
620
    sed 's,INSERT_PROVISIONING_HERE,'"$provisioning_commands"',' >> \
621 1593:83412a0a2389 Chris
        "$managerdir/Dockerfile.gen"
622 1587:d8949733849d Chris
623 1586:d0d59d12db94 Chris
cd "$rootdir"
624
625 1569:26a4f99ec679 Chris
dockertag="cannam/soundsoftware-site"
626
627 1593:83412a0a2389 Chris
sudo docker build -t "$dockertag" -f "deploy/docker/Dockerfile.gen" .
628 1571:4c2b25b7e85f Chris
sudo docker run -p 8080:80 -d "$dockertag"
629 1569:26a4f99ec679 Chris
630 1577:e38eee2e1d47 Chris
#!/bin/bash
631
632
set -e
633
634 1589:94669513c53c Chris
# Install necessary system packages. This assumes we are deploying on
635
# Ubuntu 16.04.
636
637
# We aim to make all of these provisioning scripts non-destructive if
638
# run more than once. In this case, running the script again will
639
# install any outstanding updates.
640
641 1587:d8949733849d Chris
apt-get update && \
642
    apt-get dist-upgrade -y && \
643
    apt-get install -y \
644
            ack-grep \
645
            apache2 \
646
            apache2-dev \
647
            apt-utils \
648
            build-essential \
649
            cron \
650 1582:f26dc3004b3f Chris
            curl \
651
            doxygen \
652 1587:d8949733849d Chris
            exim4 \
653 1582:f26dc3004b3f Chris
            git \
654 1587:d8949733849d Chris
            graphviz \
655
            imagemagick \
656
            libapache-dbi-perl \
657
            libapache2-mod-perl2 \
658
            libapr1-dev \
659
            libaprutil1-dev \
660
            libauthen-simple-ldap-perl \
661
            libcurl4-openssl-dev \
662
            libdbd-pg-perl \
663
            libpq-dev \
664
            libmagickwand-dev \
665
            libio-socket-ssl-perl \
666
            logrotate \
667 1582:f26dc3004b3f Chris
            mercurial \
668 1589:94669513c53c Chris
            openjdk-9-jdk-headless \
669 1582:f26dc3004b3f Chris
            postgresql \
670 1587:d8949733849d Chris
            rsync \
671
            ruby \
672
            ruby-dev \
673
            sudo
674 1582:f26dc3004b3f Chris
675 1587:d8949733849d Chris
locale-gen en_US.UTF-8
676 1582:f26dc3004b3f Chris
677
678 1577:e38eee2e1d47 Chris
#!/bin/bash
679
680
set -e
681
682 1589:94669513c53c Chris
# Phusion Passenger as application server.
683
# This gets installed through gem, not apt, and we ask for a specific
684
# version (the last in the 4.0.x line).
685 1577:e38eee2e1d47 Chris
686
if [ ! -f /var/lib/gems/2.3.0/gems/passenger-4.0.60/buildout/apache2/mod_passenger.so ]; then
687
    gem install passenger -v 4.0.60 --no-rdoc --no-ri
688
    passenger-install-apache2-module --languages=ruby
689
fi
690
691
#!/bin/bash
692
693
set -e
694
695 1590:c18460da6620 Chris
# The webapp directory is owned and run by the code user, in group
696
# www-data. The repos and other things served directly are the other
697
# way around -- owned by the www-data user, in group code.
698 1589:94669513c53c Chris
699 1590:c18460da6620 Chris
for user in code docgen ; do
700
    if ! grep -q "^$user:" /etc/passwd ; then
701
        groupadd "$user"
702
        useradd -g "$user" -G www-data "$user"
703
    fi
704
done
705 1577:e38eee2e1d47 Chris
706
#!/bin/bash
707
708
set -e
709
710 1589:94669513c53c Chris
# We might be running in one of two ways:
711
#
712
# 1. The code directory is already at /var/www/code, either because a
713
# previous provisioning step has imported it there or because this
714
# script has been run before -- in this situation all we do is
715
# re-check the ownership and permissions. OR
716
#
717
# 2. The code directory has not yet been copied to /var/www/code, in
718
# which case we expect to find it at /code-to-deploy, e.g. as a
719
# Vagrant shared folder, and we copy it over from there. (We don't
720
# deploy directly from shared folders as we might not be able to
721
# manipulate ownership and permissions properly there.)
722
723 1577:e38eee2e1d47 Chris
if [ ! -d /var/www/code ]; then
724 1587:d8949733849d Chris
    if [ ! -d /code-to-deploy ]; then
725 1589:94669513c53c Chris
        echo "ERROR: Expected to find code tree at /var/www/code or /code-to-deploy: is the deployment script being invoked correctly?"
726 1587:d8949733849d Chris
        exit 2
727
    fi
728
    cp -a /code-to-deploy /var/www/code
729 1577:e38eee2e1d47 Chris
fi
730
731 1587:d8949733849d Chris
chown -R code.www-data /var/www/code
732
find /var/www/code -type d -exec chmod g+s \{\} \;
733
734
735 1577:e38eee2e1d47 Chris
#!/bin/bash
736
737
set -e
738
739 1589:94669513c53c Chris
# In a real deployment, /var/hg is probably mounted from somewhere
740
# else. But in an empty deployment we need to create it, and in both
741
# cases we set up the config files with their current versions here.
742
743 1577:e38eee2e1d47 Chris
if [ ! -f /var/hg/index.cgi ]; then
744
    mkdir -p /var/hg
745
fi
746 1589:94669513c53c Chris
747
cp /var/www/code/deploy/config/index.cgi /var/hg/
748
cp /var/www/code/deploy/config/hgweb.config /var/hg/
749
750
chmod +x /var/hg/index.cgi
751
752 1590:c18460da6620 Chris
chown -R www-data.code /var/hg
753 1589:94669513c53c Chris
find /var/hg -type d -exec chmod g+s \{\} \;
754
755 1577:e38eee2e1d47 Chris
#!/bin/bash
756
757
set -e
758
759 1589:94669513c53c Chris
# Copy across the database config file (the source file has presumably
760
# been generated from a skeleton, earlier in provisioning)
761
762 1593:83412a0a2389 Chris
infile=/var/www/code/deploy/config/database.yml.gen
763 1589:94669513c53c Chris
outfile=/var/www/code/config/database.yml
764 1587:d8949733849d Chris
765 1589:94669513c53c Chris
if [ ! -f "$outfile" ]; then
766
    if [ ! -f "$infile" ]; then
767
        echo "ERROR: Database config file $infile not found - has the database secret been interpolated from $infile.in correctly?"
768
        exit 2
769
    fi
770
    cp "$infile" "$outfile"
771 1577:e38eee2e1d47 Chris
fi
772
773
#!/bin/bash
774
775
set -e
776
777 1589:94669513c53c Chris
# Install Ruby gems for the web app.
778
779
# We aim to make all of these provisioning scripts non-destructive if
780
# run more than once. In this case, running the script again will
781
# install any outstanding updates.
782
783 1577:e38eee2e1d47 Chris
cd /var/www/code
784
gem install bundler
785
bundle install
786
787
#!/bin/bash
788
789
set -e
790
791 1589:94669513c53c Chris
# Create a session token if it hasn't already been created.
792
793 1577:e38eee2e1d47 Chris
cd /var/www/code
794
795 1589:94669513c53c Chris
if [ ! -f config/initializers/secret_token.rb ]; then
796
    bundle exec rake generate_secret_token
797
fi
798
799
800 1577:e38eee2e1d47 Chris
#!/bin/bash
801
802
set -e
803
804 1589:94669513c53c Chris
# Start the database and if a dump file is found, load it. The dump
805
# file is then deleted so that the db won't be overwritten on
806
# subsequent runs. (The original repo contains no dump file, so it
807
# should exist only if you have provided some data to load.)
808
809 1577:e38eee2e1d47 Chris
/etc/init.d/postgresql start
810
811
cd /var/www/code
812
813
if [ -f postgres-dumpall ]; then
814
    chmod ugo+r postgres-dumpall
815
    sudo -u postgres psql -f postgres-dumpall postgres
816 1589:94669513c53c Chris
    rm postgres-dumpall
817 1577:e38eee2e1d47 Chris
fi
818
819
#!/bin/bash
820
821
set -e
822
823 1589:94669513c53c Chris
# Install the Apache mod_perl module used for hg repo access control
824
825 1577:e38eee2e1d47 Chris
if [ ! -f /usr/local/lib/site_perl/Apache/Authn/SoundSoftware.pm ]; then
826
    mkdir -p /usr/local/lib/site_perl/Apache/Authn/
827 1589:94669513c53c Chris
    cp /var/www/code/extra/soundsoftware/SoundSoftware.pm \
828
       /usr/local/lib/site_perl/Apache/Authn/
829 1577:e38eee2e1d47 Chris
fi
830
831
#!/bin/bash
832
833
set -e
834
835 1589:94669513c53c Chris
# Install Apache config files and module loaders
836
837 1577:e38eee2e1d47 Chris
cd /var/www/code
838
839 1593:83412a0a2389 Chris
codeconffile=/var/www/code/deploy/config/code.conf.gen
840 1587:d8949733849d Chris
841
if [ ! -f "$codeconffile" ]; then
842 1593:83412a0a2389 Chris
    echo "ERROR: Apache config file $codeconffile not found - has the database secret been interpolated from its input file correctly?"
843 1587:d8949733849d Chris
    exit 2
844
fi
845
846 1577:e38eee2e1d47 Chris
if [ ! -f /etc/apache2/sites-enabled/10-code.conf ]; then
847
848
    rm -f /etc/apache2/sites-enabled/000-default.conf
849
850 1587:d8949733849d Chris
    cp deploy/config/passenger.conf /etc/apache2/mods-available/
851
    cp deploy/config/passenger.load /etc/apache2/mods-available/
852
    cp deploy/config/perl.conf      /etc/apache2/mods-available/
853 1577:e38eee2e1d47 Chris
854
    ln -s ../mods-available/passenger.conf  /etc/apache2/mods-enabled/
855
    ln -s ../mods-available/passenger.load  /etc/apache2/mods-enabled/
856
    ln -s ../mods-available/perl.conf       /etc/apache2/mods-enabled/
857
    ln -s ../mods-available/expires.load    /etc/apache2/mods-enabled/
858
    ln -s ../mods-available/rewrite.load    /etc/apache2/mods-enabled/
859 1578:06ca2df3d7ca Chris
    ln -s ../mods-available/cgi.load        /etc/apache2/mods-enabled/
860 1577:e38eee2e1d47 Chris
861 1587:d8949733849d Chris
    cp "$codeconffile" /etc/apache2/sites-available/code.conf
862 1577:e38eee2e1d47 Chris
    ln -s ../sites-available/code.conf /etc/apache2/sites-enabled/10-code.conf
863
864
    apache2ctl configtest
865
866
fi
867
868 1588:9149f2098413 Chris
#!/bin/bash
869
870
set -e
871
872 1589:94669513c53c Chris
# In case we are running without a properly mounted /var/hg directory,
873
# check for the existence of one repo and, if absent, attempt to clone
874
# it so that we have something we can serve for test purposes.
875
876 1588:9149f2098413 Chris
if [ ! -d /var/hg/vamp-plugin-sdk ]; then
877
    echo "Cloning vamp-plugin-sdk repo for testing..."
878
    cd /var/hg
879
    hg clone https://code.soundsoftware.ac.uk/hg/vamp-plugin-sdk
880 1590:c18460da6620 Chris
    chown -R www-data.code vamp-plugin-sdk
881 1588:9149f2098413 Chris
fi
882 1590:c18460da6620 Chris
#!/bin/bash
883
884
set -e
885
886 1596:45b0571b684d Chris
# Copy docgen scripts, including the generated scripts with
887
# interpolated API key etc, to the directory they will be run from.
888
889
# These are run from cron jobs to do the (currently daily) update of
890
# extracted documentation from Doxygen, Javadoc, and MATLAB, and to
891
# enable displaying them with the redmine_embedded plugin. (The API
892
# key is needed to automatically switch on the embedded module for a
893
# project the first time its docs are extracted.)
894 1590:c18460da6620 Chris
895
cd /var/www/code
896
897
mkdir -p docgen
898
899
for file in \
900
    doxysafe.pl \
901
    extract-doxygen.sh \
902
    extract-javadoc.sh \
903
    extract-matlabdocs.sh \
904
    matlab-docs.conf \
905
    matlab-docs-credit.html \
906
    matlab-docs.pl ; do
907
    if [ ! -f docgen/"$file" ]; then
908
        cp extra/soundsoftware/"$file" docgen/
909
    fi
910
done
911
912 1593:83412a0a2389 Chris
for file in \
913
    extract-docs.sh ; do
914
    if [ ! -f docgen/"$file" ]; then
915
        cp deploy/config/"$file".gen docgen/"$file"
916
    fi
917
done
918
919 1590:c18460da6620 Chris
chown code.www-data docgen/*
920
chmod +x docgen/*.sh
921
922
#!/bin/bash
923
924
set -e
925
926 1596:45b0571b684d Chris
# Copy reposman (repository manager) scripts, including the generated
927
# scripts with interpolated API key etc, to the directory they will be
928
# run from.
929
930
# There are two sets of scripts here:
931
#
932
# 1. The reposman script that plods through all the projects that have
933
# repositories defined, creates those repositories on disc, and
934
# registers their locations with the projects. This happens often,
935
# currently every minute.
936
#
937
# 2. The external repo management script that plods through all the
938
# projects that have external repositories defined, clones or updates
939
# those external repos to their local locations, and if necessary
940
# registers them with the projects. This happens less often, currently
941
# every hour.
942 1590:c18460da6620 Chris
943
cd /var/www/code
944
945
mkdir -p reposman
946
947
for file in \
948
    convert-external-repos.rb \
949
    reposman-soundsoftware.rb \
950
    run-hginit.sh \
951
    update-external-repo.sh ; do
952
    if [ ! -f reposman/"$file" ]; then
953
        cp extra/soundsoftware/"$file" reposman/
954
    fi
955
done
956
957
for file in \
958
    run-external.sh \
959
    run-reposman.sh ; do
960
    if [ ! -f reposman/"$file" ]; then
961 1593:83412a0a2389 Chris
        cp deploy/config/"$file".gen reposman/"$file"
962 1590:c18460da6620 Chris
    fi
963
done
964
965
chown code.www-data reposman/*
966
chmod +x reposman/*.sh
967
chmod +x reposman/*.rb
968
969
touch /var/log/reposman.log
970
touch /var/log/external-repos.log
971
chown www-data.code /var/log/reposman.log
972
chown www-data.code /var/log/external-repos.log
973
974
#!/bin/bash
975
976
set -e
977
978
# Initialise directories used as targets for cron activity (if they
979
# don't already exist)
980
981
for dir in \
982
    /var/files/backups \
983
    /var/doc \
984
    /var/files/git-mirror ; do
985
    if [ ! -d "$dir" ]; then
986
        mkdir -p "$dir"
987
        chown -R code.www-data "$dir"
988
        chmod g+s "$dir"
989
    fi
990
done
991
992
# Copy cron scripts to the appropriate destinations
993
994
cd /var/www/code
995
996
if [ ! -d /etc/cron.minutely ]; then
997
    mkdir -p /etc/cron.minutely
998
    echo '*  *    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.minutely )' >> /etc/crontab
999
fi
1000
1001
for t in minutely hourly daily monthly; do
1002
    for s in deploy/config/cron.$t/[0-9]* ; do
1003
        name=$(basename $s)
1004
        dest="/etc/cron.$t/$name"
1005
        if [ ! -f "$dest" ]; then
1006
            cp "$s" "$dest"
1007
            chmod +x "$dest"
1008
        fi
1009
    done
1010
done
1011
1012
1013
1014
#!/bin/bash
1015
1016
cd /var/www/code
1017
cp deploy/config/logrotate.conf /etc/logrotate.conf
1018 1581:ae8043b014c7 Chris
#!/bin/bash
1019
1020
set -e
1021
1022 1589:94669513c53c Chris
# Last action: start the webserver
1023
1024 1581:ae8043b014c7 Chris
apache2ctl restart
1025
1026 1596:45b0571b684d Chris
#!/bin/bash
1027
1028
# The big problem with this test script is that it needs the cron
1029
# scripts that generate some of this stuff to have been run at least
1030
# once
1031
1032
usage() {
1033
    echo 1>&2
1034
    echo "Usage: $0 <uri-base>" 1>&2
1035
    echo 1>&2
1036
    echo "  e.g. $0 https://code.soundsoftware.ac.uk" 1>&2
1037
    echo "    or $0 http://localhost:8080" 1>&2
1038
    echo 1>&2
1039
    exit 2
1040
}
1041
1042
uribase="$1"
1043
if [ -z "$uribase" ]; then
1044
    usage
1045
fi
1046
1047
set -eu
1048
1049 1597:eeacb8332051 Chris
# A project known to exist, be public, and have a repository
1050
project_with_repo=vamp-plugin-sdk
1051
1052
# A project known to exist, be public, and have embedded documentation
1053
project_with_docs=vamp-plugin-sdk
1054
1055
# A project known to exist, be public, and have a bibliography
1056
project_with_biblio=sonic-visualiser
1057 1596:45b0571b684d Chris
1058
tried=0
1059
succeeded=0
1060
1061
mydir=$(dirname "$0")
1062
1063
try() {
1064
    mkdir -p "$mydir/output"
1065
    origin=$(pwd)
1066
    cd "$mydir/output"
1067
    path="$1"
1068
    description="$2"
1069
    url="$uribase$path"
1070
    echo
1071
    echo "Trying \"$description\" [$url]..."
1072
    echo
1073
    if wget "$url" ; then
1074
        echo "+++ Succeeded"
1075
        succeeded=$(($succeeded + 1))
1076
    else
1077
        echo "--- FAILED"
1078
    fi
1079 1597:eeacb8332051 Chris
    tried=$(($tried + 1))
1080
    cd "$origin"
1081 1596:45b0571b684d Chris
}
1082
1083
try "/" "Front page"
1084 1597:eeacb8332051 Chris
try "/projects/$project_with_repo" "Project page"
1085
try "/projects/$project_with_biblio" "Project page with bibliography"
1086
try "/projects/$project_with_repo/repository" "Repository page"
1087
try "/hg/$project_with_repo" "Mercurial repo"
1088
try "/projects/$project_with_docs/embedded" "Project documentation page (from docgen cron script)"
1089
try "/git/$project_with_repo/info/refs" "Git repo mirror"
1090 1596:45b0571b684d Chris
1091
echo
1092
echo "Passed $succeeded of $tried"
1093
echo
1094
1095 1577:e38eee2e1d47 Chris
# -*- mode: ruby -*-
1096
# vi: set ft=ruby :
1097
1098
Vagrant.configure("2") do |config|
1099 1583:0dcd4f8c2b8a Chris
  config.vm.box = "ubuntu/xenial64"
1100 1577:e38eee2e1d47 Chris
  config.vm.network "forwarded_port", guest: 80, host: 8080
1101 1587:d8949733849d Chris
  config.vm.synced_folder "../..", "/code-to-deploy"
1102 1577:e38eee2e1d47 Chris
  config.vm.provision :shell, path: "vagrant-provision.sh"
1103
end
1104 1581:ae8043b014c7 Chris
#!/bin/bash
1105
1106 1586:d0d59d12db94 Chris
mydir=$(dirname "$0")
1107 1593:83412a0a2389 Chris
. "$mydir"/../any/prepare.sh
1108 1581:ae8043b014c7 Chris
1109
cd "$managerdir"
1110
vagrant up
1111
1112 1577:e38eee2e1d47 Chris
#!/bin/bash
1113
1114
#!!! still not covered:
1115
# * https
1116 1590:c18460da6620 Chris
# * http auth for API (/sys) and /admin interfaces
1117 1593:83412a0a2389 Chris
# * sending email
1118 1577:e38eee2e1d47 Chris
1119
set -e
1120
1121 1590:c18460da6620 Chris
for f in /code-to-deploy/deploy/provision.d/[0-9]*.sh ; do
1122 1577:e38eee2e1d47 Chris
    case "$f" in
1123
        *~) ;;
1124 1593:83412a0a2389 Chris
        *) echo "Running provisioning script: $f"
1125 1577:e38eee2e1d47 Chris
           /bin/bash "$f";;
1126
    esac
1127
done
1128
1129 1593:83412a0a2389 Chris
echo "All provisioning scripts complete"