To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / deploy / provision.d @ 1601:07deb8466f65
| 1 | 1577:e38eee2e1d47 | Chris | #!/bin/bash |
|---|---|---|---|
| 2 | |||
| 3 | set -e |
||
| 4 | |||
| 5 | 1589:94669513c53c | Chris | # Install necessary system packages. This assumes we are deploying on |
| 6 | # Ubuntu 16.04. |
||
| 7 | |||
| 8 | # We aim to make all of these provisioning scripts non-destructive if |
||
| 9 | # run more than once. In this case, running the script again will |
||
| 10 | # install any outstanding updates. |
||
| 11 | |||
| 12 | 1587:d8949733849d | Chris | apt-get update && \ |
| 13 | apt-get dist-upgrade -y && \ |
||
| 14 | apt-get install -y \ |
||
| 15 | ack-grep \ |
||
| 16 | apache2 \ |
||
| 17 | apache2-dev \ |
||
| 18 | apt-utils \ |
||
| 19 | build-essential \ |
||
| 20 | cron \ |
||
| 21 | 1582:f26dc3004b3f | Chris | curl \ |
| 22 | doxygen \ |
||
| 23 | 1587:d8949733849d | Chris | exim4 \ |
| 24 | 1582:f26dc3004b3f | Chris | git \ |
| 25 | 1587:d8949733849d | Chris | graphviz \ |
| 26 | imagemagick \ |
||
| 27 | libapache-dbi-perl \ |
||
| 28 | libapache2-mod-perl2 \ |
||
| 29 | libapr1-dev \ |
||
| 30 | libaprutil1-dev \ |
||
| 31 | libauthen-simple-ldap-perl \ |
||
| 32 | libcurl4-openssl-dev \ |
||
| 33 | libdbd-pg-perl \ |
||
| 34 | libpq-dev \ |
||
| 35 | libmagickwand-dev \ |
||
| 36 | libio-socket-ssl-perl \ |
||
| 37 | logrotate \ |
||
| 38 | 1582:f26dc3004b3f | Chris | mercurial \ |
| 39 | 1600:ed9c467ef922 | Chris | mercurial-git \ |
| 40 | 1589:94669513c53c | Chris | openjdk-9-jdk-headless \ |
| 41 | 1582:f26dc3004b3f | Chris | postgresql \ |
| 42 | 1587:d8949733849d | Chris | rsync \ |
| 43 | ruby \ |
||
| 44 | ruby-dev \ |
||
| 45 | sudo |
||
| 46 | 1582:f26dc3004b3f | Chris | |
| 47 | 1587:d8949733849d | Chris | locale-gen en_US.UTF-8 |
| 48 | 1582:f26dc3004b3f | Chris | |
| 49 | |||
| 50 | 1577:e38eee2e1d47 | Chris | #!/bin/bash |
| 51 | |||
| 52 | set -e |
||
| 53 | |||
| 54 | 1589:94669513c53c | Chris | # Phusion Passenger as application server. |
| 55 | # This gets installed through gem, not apt, and we ask for a specific |
||
| 56 | # version (the last in the 4.0.x line). |
||
| 57 | 1577:e38eee2e1d47 | Chris | |
| 58 | if [ ! -f /var/lib/gems/2.3.0/gems/passenger-4.0.60/buildout/apache2/mod_passenger.so ]; then |
||
| 59 | gem install passenger -v 4.0.60 --no-rdoc --no-ri |
||
| 60 | passenger-install-apache2-module --languages=ruby |
||
| 61 | fi |
||
| 62 | |||
| 63 | #!/bin/bash |
||
| 64 | |||
| 65 | set -e |
||
| 66 | |||
| 67 | 1590:c18460da6620 | Chris | # The webapp directory is owned and run by the code user, in group |
| 68 | # www-data. The repos and other things served directly are the other |
||
| 69 | # way around -- owned by the www-data user, in group code. |
||
| 70 | 1589:94669513c53c | Chris | |
| 71 | 1590:c18460da6620 | Chris | for user in code docgen ; do |
| 72 | if ! grep -q "^$user:" /etc/passwd ; then |
||
| 73 | groupadd "$user" |
||
| 74 | useradd -g "$user" -G www-data "$user" |
||
| 75 | fi |
||
| 76 | done |
||
| 77 | 1577:e38eee2e1d47 | Chris | |
| 78 | #!/bin/bash |
||
| 79 | |||
| 80 | set -e |
||
| 81 | |||
| 82 | 1589:94669513c53c | Chris | # We might be running in one of two ways: |
| 83 | # |
||
| 84 | # 1. The code directory is already at /var/www/code, either because a |
||
| 85 | # previous provisioning step has imported it there or because this |
||
| 86 | # script has been run before -- in this situation all we do is |
||
| 87 | # re-check the ownership and permissions. OR |
||
| 88 | # |
||
| 89 | # 2. The code directory has not yet been copied to /var/www/code, in |
||
| 90 | # which case we expect to find it at /code-to-deploy, e.g. as a |
||
| 91 | # Vagrant shared folder, and we copy it over from there. (We don't |
||
| 92 | # deploy directly from shared folders as we might not be able to |
||
| 93 | # manipulate ownership and permissions properly there.) |
||
| 94 | |||
| 95 | 1577:e38eee2e1d47 | Chris | if [ ! -d /var/www/code ]; then |
| 96 | 1587:d8949733849d | Chris | if [ ! -d /code-to-deploy ]; then |
| 97 | 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?" |
| 98 | 1587:d8949733849d | Chris | exit 2 |
| 99 | fi |
||
| 100 | cp -a /code-to-deploy /var/www/code |
||
| 101 | 1577:e38eee2e1d47 | Chris | fi |
| 102 | |||
| 103 | 1587:d8949733849d | Chris | chown -R code.www-data /var/www/code |
| 104 | find /var/www/code -type d -exec chmod g+s \{\} \;
|
||
| 105 | |||
| 106 | |||
| 107 | 1577:e38eee2e1d47 | Chris | #!/bin/bash |
| 108 | |||
| 109 | set -e |
||
| 110 | |||
| 111 | 1589:94669513c53c | Chris | # In a real deployment, /var/hg is probably mounted from somewhere |
| 112 | # else. But in an empty deployment we need to create it, and in both |
||
| 113 | # cases we set up the config files with their current versions here. |
||
| 114 | |||
| 115 | 1577:e38eee2e1d47 | Chris | if [ ! -f /var/hg/index.cgi ]; then |
| 116 | mkdir -p /var/hg |
||
| 117 | fi |
||
| 118 | 1589:94669513c53c | Chris | |
| 119 | cp /var/www/code/deploy/config/index.cgi /var/hg/ |
||
| 120 | cp /var/www/code/deploy/config/hgweb.config /var/hg/ |
||
| 121 | |||
| 122 | chmod +x /var/hg/index.cgi |
||
| 123 | |||
| 124 | 1590:c18460da6620 | Chris | chown -R www-data.code /var/hg |
| 125 | 1589:94669513c53c | Chris | find /var/hg -type d -exec chmod g+s \{\} \;
|
| 126 | |||
| 127 | 1577:e38eee2e1d47 | Chris | #!/bin/bash |
| 128 | |||
| 129 | set -e |
||
| 130 | |||
| 131 | 1589:94669513c53c | Chris | # Copy across the database config file (the source file has presumably |
| 132 | # been generated from a skeleton, earlier in provisioning) |
||
| 133 | |||
| 134 | 1593:83412a0a2389 | Chris | infile=/var/www/code/deploy/config/database.yml.gen |
| 135 | 1589:94669513c53c | Chris | outfile=/var/www/code/config/database.yml |
| 136 | 1587:d8949733849d | Chris | |
| 137 | 1589:94669513c53c | Chris | if [ ! -f "$outfile" ]; then |
| 138 | if [ ! -f "$infile" ]; then |
||
| 139 | echo "ERROR: Database config file $infile not found - has the database secret been interpolated from $infile.in correctly?" |
||
| 140 | exit 2 |
||
| 141 | fi |
||
| 142 | cp "$infile" "$outfile" |
||
| 143 | 1577:e38eee2e1d47 | Chris | fi |
| 144 | |||
| 145 | #!/bin/bash |
||
| 146 | |||
| 147 | set -e |
||
| 148 | |||
| 149 | 1589:94669513c53c | Chris | # Install Ruby gems for the web app. |
| 150 | |||
| 151 | # We aim to make all of these provisioning scripts non-destructive if |
||
| 152 | # run more than once. In this case, running the script again will |
||
| 153 | # install any outstanding updates. |
||
| 154 | |||
| 155 | 1577:e38eee2e1d47 | Chris | cd /var/www/code |
| 156 | gem install bundler |
||
| 157 | bundle install |
||
| 158 | |||
| 159 | #!/bin/bash |
||
| 160 | |||
| 161 | set -e |
||
| 162 | |||
| 163 | 1589:94669513c53c | Chris | # Create a session token if it hasn't already been created. |
| 164 | |||
| 165 | 1577:e38eee2e1d47 | Chris | cd /var/www/code |
| 166 | |||
| 167 | 1589:94669513c53c | Chris | if [ ! -f config/initializers/secret_token.rb ]; then |
| 168 | bundle exec rake generate_secret_token |
||
| 169 | fi |
||
| 170 | |||
| 171 | |||
| 172 | 1577:e38eee2e1d47 | Chris | #!/bin/bash |
| 173 | |||
| 174 | set -e |
||
| 175 | |||
| 176 | 1589:94669513c53c | Chris | # Start the database and if a dump file is found, load it. The dump |
| 177 | # file is then deleted so that the db won't be overwritten on |
||
| 178 | # subsequent runs. (The original repo contains no dump file, so it |
||
| 179 | # should exist only if you have provided some data to load.) |
||
| 180 | |||
| 181 | 1577:e38eee2e1d47 | Chris | /etc/init.d/postgresql start |
| 182 | |||
| 183 | cd /var/www/code |
||
| 184 | |||
| 185 | if [ -f postgres-dumpall ]; then |
||
| 186 | chmod ugo+r postgres-dumpall |
||
| 187 | sudo -u postgres psql -f postgres-dumpall postgres |
||
| 188 | 1589:94669513c53c | Chris | rm postgres-dumpall |
| 189 | 1577:e38eee2e1d47 | Chris | fi |
| 190 | |||
| 191 | #!/bin/bash |
||
| 192 | |||
| 193 | set -e |
||
| 194 | |||
| 195 | 1589:94669513c53c | Chris | # Install the Apache mod_perl module used for hg repo access control |
| 196 | |||
| 197 | 1577:e38eee2e1d47 | Chris | if [ ! -f /usr/local/lib/site_perl/Apache/Authn/SoundSoftware.pm ]; then |
| 198 | mkdir -p /usr/local/lib/site_perl/Apache/Authn/ |
||
| 199 | 1589:94669513c53c | Chris | cp /var/www/code/extra/soundsoftware/SoundSoftware.pm \ |
| 200 | /usr/local/lib/site_perl/Apache/Authn/ |
||
| 201 | 1577:e38eee2e1d47 | Chris | fi |
| 202 | |||
| 203 | #!/bin/bash |
||
| 204 | |||
| 205 | set -e |
||
| 206 | |||
| 207 | 1589:94669513c53c | Chris | # Install Apache config files and module loaders |
| 208 | |||
| 209 | 1577:e38eee2e1d47 | Chris | cd /var/www/code |
| 210 | |||
| 211 | 1593:83412a0a2389 | Chris | codeconffile=/var/www/code/deploy/config/code.conf.gen |
| 212 | 1587:d8949733849d | Chris | |
| 213 | if [ ! -f "$codeconffile" ]; then |
||
| 214 | 1593:83412a0a2389 | Chris | echo "ERROR: Apache config file $codeconffile not found - has the database secret been interpolated from its input file correctly?" |
| 215 | 1587:d8949733849d | Chris | exit 2 |
| 216 | fi |
||
| 217 | |||
| 218 | 1577:e38eee2e1d47 | Chris | if [ ! -f /etc/apache2/sites-enabled/10-code.conf ]; then |
| 219 | |||
| 220 | rm -f /etc/apache2/sites-enabled/000-default.conf |
||
| 221 | |||
| 222 | 1587:d8949733849d | Chris | cp deploy/config/passenger.conf /etc/apache2/mods-available/ |
| 223 | cp deploy/config/passenger.load /etc/apache2/mods-available/ |
||
| 224 | cp deploy/config/perl.conf /etc/apache2/mods-available/ |
||
| 225 | 1577:e38eee2e1d47 | Chris | |
| 226 | ln -s ../mods-available/passenger.conf /etc/apache2/mods-enabled/ |
||
| 227 | ln -s ../mods-available/passenger.load /etc/apache2/mods-enabled/ |
||
| 228 | ln -s ../mods-available/perl.conf /etc/apache2/mods-enabled/ |
||
| 229 | ln -s ../mods-available/expires.load /etc/apache2/mods-enabled/ |
||
| 230 | ln -s ../mods-available/rewrite.load /etc/apache2/mods-enabled/ |
||
| 231 | 1578:06ca2df3d7ca | Chris | ln -s ../mods-available/cgi.load /etc/apache2/mods-enabled/ |
| 232 | 1577:e38eee2e1d47 | Chris | |
| 233 | 1587:d8949733849d | Chris | cp "$codeconffile" /etc/apache2/sites-available/code.conf |
| 234 | 1577:e38eee2e1d47 | Chris | ln -s ../sites-available/code.conf /etc/apache2/sites-enabled/10-code.conf |
| 235 | |||
| 236 | apache2ctl configtest |
||
| 237 | |||
| 238 | fi |
||
| 239 | |||
| 240 | 1588:9149f2098413 | Chris | #!/bin/bash |
| 241 | |||
| 242 | set -e |
||
| 243 | |||
| 244 | 1589:94669513c53c | Chris | # In case we are running without a properly mounted /var/hg directory, |
| 245 | # check for the existence of one repo and, if absent, attempt to clone |
||
| 246 | # it so that we have something we can serve for test purposes. |
||
| 247 | |||
| 248 | 1588:9149f2098413 | Chris | if [ ! -d /var/hg/vamp-plugin-sdk ]; then |
| 249 | echo "Cloning vamp-plugin-sdk repo for testing..." |
||
| 250 | cd /var/hg |
||
| 251 | hg clone https://code.soundsoftware.ac.uk/hg/vamp-plugin-sdk |
||
| 252 | 1590:c18460da6620 | Chris | chown -R www-data.code vamp-plugin-sdk |
| 253 | 1588:9149f2098413 | Chris | fi |
| 254 | 1598:073a75bf07fb | Chris | #!/bin/bash |
| 255 | |||
| 256 | set -e |
||
| 257 | |||
| 258 | # Initialise directories used as targets for cron activity (if they |
||
| 259 | # don't already exist) |
||
| 260 | |||
| 261 | # Reminder: the webapp directory is owned and run by the code user, in |
||
| 262 | # group www-data. The repos and other things served directly are |
||
| 263 | # usually the other way around -- owned by the www-data user, in group |
||
| 264 | # code. I don't recall whether there is a good reason for this. |
||
| 265 | |||
| 266 | for dir in \ |
||
| 267 | /var/files/backups \ |
||
| 268 | /var/doc \ |
||
| 269 | /var/files/git-mirror ; do |
||
| 270 | if [ ! -d "$dir" ]; then |
||
| 271 | mkdir -p "$dir" |
||
| 272 | chown -R code.www-data "$dir" |
||
| 273 | chmod g+s "$dir" |
||
| 274 | fi |
||
| 275 | done |
||
| 276 | |||
| 277 | for dir in \ |
||
| 278 | /var/mirror ; do |
||
| 279 | if [ ! -d "$dir" ]; then |
||
| 280 | mkdir -p "$dir" |
||
| 281 | chown -R www-data.code "$dir" |
||
| 282 | chmod g+s "$dir" |
||
| 283 | fi |
||
| 284 | done |
||
| 285 | 1590:c18460da6620 | Chris | #!/bin/bash |
| 286 | |||
| 287 | set -e |
||
| 288 | |||
| 289 | 1596:45b0571b684d | Chris | # Copy docgen scripts, including the generated scripts with |
| 290 | # interpolated API key etc, to the directory they will be run from. |
||
| 291 | |||
| 292 | # These are run from cron jobs to do the (currently daily) update of |
||
| 293 | # extracted documentation from Doxygen, Javadoc, and MATLAB, and to |
||
| 294 | # enable displaying them with the redmine_embedded plugin. (The API |
||
| 295 | # key is needed to automatically switch on the embedded module for a |
||
| 296 | # project the first time its docs are extracted.) |
||
| 297 | 1590:c18460da6620 | Chris | |
| 298 | cd /var/www/code |
||
| 299 | |||
| 300 | mkdir -p docgen |
||
| 301 | |||
| 302 | for file in \ |
||
| 303 | doxysafe.pl \ |
||
| 304 | extract-doxygen.sh \ |
||
| 305 | extract-javadoc.sh \ |
||
| 306 | extract-matlabdocs.sh \ |
||
| 307 | matlab-docs.conf \ |
||
| 308 | matlab-docs-credit.html \ |
||
| 309 | matlab-docs.pl ; do |
||
| 310 | if [ ! -f docgen/"$file" ]; then |
||
| 311 | cp extra/soundsoftware/"$file" docgen/ |
||
| 312 | fi |
||
| 313 | done |
||
| 314 | |||
| 315 | 1593:83412a0a2389 | Chris | for file in \ |
| 316 | extract-docs.sh ; do |
||
| 317 | if [ ! -f docgen/"$file" ]; then |
||
| 318 | cp deploy/config/"$file".gen docgen/"$file" |
||
| 319 | fi |
||
| 320 | done |
||
| 321 | |||
| 322 | 1590:c18460da6620 | Chris | chown code.www-data docgen/* |
| 323 | chmod +x docgen/*.sh |
||
| 324 | |||
| 325 | #!/bin/bash |
||
| 326 | |||
| 327 | set -e |
||
| 328 | |||
| 329 | 1596:45b0571b684d | Chris | # Copy reposman (repository manager) scripts, including the generated |
| 330 | # scripts with interpolated API key etc, to the directory they will be |
||
| 331 | # run from. |
||
| 332 | |||
| 333 | # There are two sets of scripts here: |
||
| 334 | # |
||
| 335 | # 1. The reposman script that plods through all the projects that have |
||
| 336 | # repositories defined, creates those repositories on disc, and |
||
| 337 | # registers their locations with the projects. This happens often, |
||
| 338 | # currently every minute. |
||
| 339 | # |
||
| 340 | # 2. The external repo management script that plods through all the |
||
| 341 | # projects that have external repositories defined, clones or updates |
||
| 342 | # those external repos to their local locations, and if necessary |
||
| 343 | # registers them with the projects. This happens less often, currently |
||
| 344 | # every hour. |
||
| 345 | 1590:c18460da6620 | Chris | |
| 346 | cd /var/www/code |
||
| 347 | |||
| 348 | mkdir -p reposman |
||
| 349 | |||
| 350 | for file in \ |
||
| 351 | convert-external-repos.rb \ |
||
| 352 | reposman-soundsoftware.rb \ |
||
| 353 | run-hginit.sh \ |
||
| 354 | update-external-repo.sh ; do |
||
| 355 | if [ ! -f reposman/"$file" ]; then |
||
| 356 | cp extra/soundsoftware/"$file" reposman/ |
||
| 357 | fi |
||
| 358 | done |
||
| 359 | |||
| 360 | for file in \ |
||
| 361 | run-external.sh \ |
||
| 362 | run-reposman.sh ; do |
||
| 363 | if [ ! -f reposman/"$file" ]; then |
||
| 364 | 1593:83412a0a2389 | Chris | cp deploy/config/"$file".gen reposman/"$file" |
| 365 | 1590:c18460da6620 | Chris | fi |
| 366 | done |
||
| 367 | |||
| 368 | chown code.www-data reposman/* |
||
| 369 | chmod +x reposman/*.sh |
||
| 370 | chmod +x reposman/*.rb |
||
| 371 | |||
| 372 | touch /var/log/reposman.log |
||
| 373 | touch /var/log/external-repos.log |
||
| 374 | chown www-data.code /var/log/reposman.log |
||
| 375 | chown www-data.code /var/log/external-repos.log |
||
| 376 | |||
| 377 | #!/bin/bash |
||
| 378 | |||
| 379 | set -e |
||
| 380 | |||
| 381 | # Copy cron scripts to the appropriate destinations |
||
| 382 | |||
| 383 | cd /var/www/code |
||
| 384 | |||
| 385 | if [ ! -d /etc/cron.minutely ]; then |
||
| 386 | mkdir -p /etc/cron.minutely |
||
| 387 | echo '* * * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.minutely )' >> /etc/crontab |
||
| 388 | fi |
||
| 389 | |||
| 390 | for t in minutely hourly daily monthly; do |
||
| 391 | for s in deploy/config/cron.$t/[0-9]* ; do |
||
| 392 | name=$(basename $s) |
||
| 393 | dest="/etc/cron.$t/$name" |
||
| 394 | if [ ! -f "$dest" ]; then |
||
| 395 | cp "$s" "$dest" |
||
| 396 | chmod +x "$dest" |
||
| 397 | fi |
||
| 398 | done |
||
| 399 | done |
||
| 400 | |||
| 401 | |||
| 402 | |||
| 403 | #!/bin/bash |
||
| 404 | |||
| 405 | cd /var/www/code |
||
| 406 | cp deploy/config/logrotate.conf /etc/logrotate.conf |
||
| 407 | 1601:07deb8466f65 | Chris | #!/bin/bash |
| 408 | |||
| 409 | set -e |
||
| 410 | |||
| 411 | # Print reminders of the things that we haven't covered in the deploy |
||
| 412 | # scripts |
||
| 413 | |||
| 414 | cat <<EOF |
||
| 415 | |||
| 416 | *** APACHE SSL CONFIGURATION |
||
| 417 | |||
| 418 | The provisioning scripts set up a simple HTTP site only. Refer to |
||
| 419 | deploy/config/code-ssl.conf.in for an example HTTPS configuration |
||
| 420 | (you will of course need to provide the key/cert files). |
||
| 421 | |||
| 422 | |||
| 423 | |||
| 424 | Outgoing email is required for notifications, but has not been |
||
| 425 | configured as part of this provisioning setup. |
||
| 426 | |||
| 427 | *** STATIC FRONT PAGE |
||
| 428 | |||
| 429 | We have set up only the code/repository site -- if you want a |
||
| 430 | separate front page, remember to configure that! |
||
| 431 | |||
| 432 | EOF |
||
| 433 | 1581:ae8043b014c7 | Chris | #!/bin/bash |
| 434 | |||
| 435 | set -e |
||
| 436 | |||
| 437 | 1601:07deb8466f65 | Chris | # Last action: check & start the webserver |
| 438 | |||
| 439 | apache2ctl configtest |
||
| 440 | 1589:94669513c53c | Chris | |
| 441 | 1581:ae8043b014c7 | Chris | apache2ctl restart |