├── .gitignore ├── .pylintrc ├── .travis.yml ├── .travis ├── flow.py └── test_python_pep8_compliancy.py ├── LICENSE.txt ├── README.md ├── app ├── Dockerfile ├── __init__.py ├── ansible.cfg ├── arguments.py ├── base.py ├── containers.py ├── db.py ├── edge.py ├── init.py ├── local_setup.py ├── mirror.py ├── orchestration.py ├── orchestration │ ├── _tests │ │ ├── db-tests.yml │ │ ├── edge-tests.yml │ │ ├── mirror-tests.yml │ │ ├── plays │ │ │ ├── db │ │ │ │ ├── adminer-tests.yml │ │ │ │ ├── db-tests.yml │ │ │ │ ├── memcached-tests.yml │ │ │ │ └── phpmyadmin-tests.yml │ │ │ ├── drupal │ │ │ │ └── drupal-tests.yml │ │ │ ├── edge │ │ │ │ ├── mirror-tests.yml │ │ │ │ ├── nginx-tests.yml │ │ │ │ └── varnish-tests.yml │ │ │ ├── php │ │ │ │ ├── apache-common-tests.yml │ │ │ │ ├── apache-tests.yml │ │ │ │ ├── pecl-yaml-tests.yml │ │ │ │ └── php-tests.yml │ │ │ ├── run-db-tests.yml │ │ │ ├── run-edge-tests.yml │ │ │ ├── run-mirror-tests.yml │ │ │ ├── run-search-tests.yml │ │ │ ├── run-system-tests.yml │ │ │ ├── run-web-tests.yml │ │ │ ├── solr │ │ │ │ └── solr-configuration-tests.yml │ │ │ ├── system │ │ │ │ ├── git-tests.yml │ │ │ │ ├── ssh-keys-tests.yml │ │ │ │ └── system-setup-tests.yml │ │ │ └── tools │ │ │ │ ├── coder-tests.yml │ │ │ │ ├── codesniffer-tests.yml │ │ │ │ ├── composer-tests.yml │ │ │ │ ├── drupal-console-tests.yml │ │ │ │ ├── drush-tests.yml │ │ │ │ ├── mcstat-tests.yml │ │ │ │ ├── phantomjs-tests.yml │ │ │ │ ├── php-cs-fixer-tests.yml │ │ │ │ ├── phpmd-tests.yml │ │ │ │ ├── tideways-tests.yml │ │ │ │ └── xdebug-tests.yml │ │ ├── search-tests.yml │ │ ├── system-tests.yml │ │ └── web-tests.yml │ ├── commands │ │ ├── app-blt.yml │ │ ├── app-delete.yml │ │ ├── app-dev.yml │ │ ├── app-drupal.yml │ │ ├── app-import.yml │ │ ├── app-lightning.yml │ │ ├── app-prod.yml │ │ ├── default-php.yml │ │ ├── legacy-php.yml │ │ └── previous-php.yml │ ├── files │ │ ├── .bash_aliases │ │ ├── .git-completion.bash │ │ ├── .git-prompt.sh │ │ ├── .gitconfig │ │ ├── .gitignore │ │ ├── .gitignore-global │ │ ├── README-import.txt │ │ ├── apache-template.conf │ │ ├── apt.conf │ │ ├── composer-dev-template.json │ │ ├── composer-template.json │ │ ├── composer.json │ │ ├── db-backup.sh │ │ ├── default.vcl │ │ ├── drush.site.yml │ │ ├── drush.yml │ │ ├── nginx-template.conf │ │ ├── phpstan.neon │ │ ├── solr-conf-7.x │ │ │ ├── elevate.xml │ │ │ ├── mapping-ISOLatin1Accent.txt │ │ │ ├── protwords.txt │ │ │ ├── schema.xml │ │ │ ├── schema_extra_fields.xml │ │ │ ├── schema_extra_types.xml │ │ │ ├── solrconfig.xml │ │ │ ├── solrconfig_extra.xml │ │ │ ├── solrconfig_spellcheck.xml │ │ │ ├── solrcore.properties │ │ │ ├── stopwords.txt │ │ │ └── synonyms.txt │ │ ├── sources.list │ │ ├── ssl │ │ │ ├── nginx.crt │ │ │ └── nginx.key │ │ └── varnish │ ├── handlers.yml │ ├── hosts │ ├── plays │ │ ├── app │ │ │ ├── blt.yml │ │ │ ├── delete.yml │ │ │ ├── dev.yml │ │ │ ├── drupal.yml │ │ │ ├── import.yml │ │ │ ├── lightning.yml │ │ │ └── prod.yml │ │ ├── common │ │ │ ├── apache-installation.yml │ │ │ ├── apache-vhost-fcgi.yml │ │ │ ├── apache-vhost.yml │ │ │ ├── app-registry.yml │ │ │ ├── apt-repos.yml │ │ │ ├── apt-update.yml │ │ │ ├── database.yml │ │ │ ├── drucker-config.yml │ │ │ ├── drupal-common.yml │ │ │ ├── drush-aliases.yml │ │ │ ├── mirror-deploy.yml │ │ │ ├── mirror-downloads.yml │ │ │ └── permissions.yml │ │ ├── db │ │ │ ├── adminer.yml │ │ │ ├── db-tools.yml │ │ │ ├── memcached.yml │ │ │ ├── mysql-backup.yml │ │ │ ├── mysql.yml │ │ │ └── phpmyadmin.yml │ │ ├── drupal │ │ │ ├── drupal-create.yml │ │ │ ├── drupal-tools.yml │ │ │ └── drupal.yml │ │ ├── edge │ │ │ ├── nginx.yml │ │ │ └── varnish.yml │ │ ├── mirror │ │ │ ├── mirror-setup.yml │ │ │ └── mirror-vhost.yml │ │ ├── php │ │ │ ├── default-php.yml │ │ │ ├── default_php_ini.yml │ │ │ ├── legacy-php.yml │ │ │ ├── legacy_php_ini.yml │ │ │ ├── libyaml.yml │ │ │ ├── pecl-yaml.yml │ │ │ ├── php.yml │ │ │ ├── php_version_and_vhost_check.yml │ │ │ ├── phpfpm_process_check.yml │ │ │ ├── previous-php.yml │ │ │ └── previous_php_ini.yml │ │ ├── post-install.yml │ │ ├── solr │ │ │ ├── java.yml │ │ │ └── solr.yml │ │ ├── stack.yml │ │ ├── system │ │ │ ├── git.yml │ │ │ ├── ssh-keys.yml │ │ │ ├── ssh.yml │ │ │ └── system-setup.yml │ │ └── tools │ │ │ ├── coder.yml │ │ │ ├── codesniffer.yml │ │ │ ├── composer.yml │ │ │ ├── drupal-console.yml │ │ │ ├── drush.yml │ │ │ ├── mcstat.yml │ │ │ ├── phantomjs.yml │ │ │ ├── php-cs-fixer.yml │ │ │ ├── phpmd.yml │ │ │ ├── sass.yml │ │ │ ├── tideways.yml │ │ │ └── xdebug.yml │ ├── provisioning │ │ ├── base.yml │ │ ├── db.yml │ │ ├── edge.yml │ │ ├── mirror.yml │ │ ├── search.yml │ │ ├── ssh.yml │ │ └── web.yml │ └── vars.yml ├── requirements.py ├── requirements.txt ├── search.py ├── services.py ├── ssh.py ├── variables.py └── web.py ├── config ├── drucker ├── drucker-logo.png └── util ├── drucker-screencast.sh └── var_usage.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Ansible files. 2 | *.retry 3 | 4 | # Ignore drucker's custom config file. 5 | config 6 | 7 | # Ignore Python cache files. 8 | __pycache__ 9 | *.pyc 10 | 11 | # Ignore Mac OS files 12 | .DS_Store 13 | .AppleDouble 14 | .LSOverride 15 | .Spotlight-V100 16 | .Trashes 17 | 18 | # Ignore Windows files 19 | ._* 20 | Thumbs.db 21 | ehthumbs.db 22 | Desktop.ini 23 | $RECYCLE.BIN/ 24 | 25 | ####################### IDEs ####################### 26 | .vscode/settings.json 27 | 28 | # Eclipse 29 | *.pydevproject 30 | .project 31 | .metadata 32 | tmp/** 33 | tmp/**/* 34 | *.tmp 35 | *.bak 36 | *.swp 37 | *~.nib 38 | local.properties 39 | .classpath 40 | .settings/ 41 | .loadpath 42 | *.launch 43 | 44 | # CDT-specific 45 | .cproject 46 | 47 | # PDT-specific 48 | .buildpathk 49 | 50 | # Emacs 51 | *~ 52 | \#*\# 53 | /.emacs.desktop 54 | /.emacs.desktop.lock 55 | *.elc 56 | auto-save-list 57 | tramp 58 | .\#* 59 | 60 | #Netbeans IDE 61 | nbproject 62 | nbproject/* 63 | 64 | # PHPStorm 65 | .idea/ 66 | atlassian-ide-plugin.xml 67 | ####################### END IDEs ####################### 68 | 69 | # Exports 70 | *.gz 71 | *.sql 72 | *.zip -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3.6 3 | dist: trusty 4 | sudo: required 5 | 6 | script: ./.travis/test_$t.py $a 7 | 8 | matrix: 9 | fast_finish: true 10 | include: 11 | - env: t=python_pep8_compliancy 12 | install: pip install pycodestyle pylint click 13 | -------------------------------------------------------------------------------- /.travis/flow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Test, output and flow-control helpers.""" 3 | import os 4 | import sys 5 | 6 | 7 | def banner(caller, subtext=None, char='#'): 8 | """Print the head-banner for a test-script.""" 9 | caller = os.path.basename(caller) 10 | caller = os.path.splitext(caller)[0].lstrip('test_').upper() 11 | if subtext and "\n" in subtext: 12 | caller = "%s:\n%s" % (caller, subtext) 13 | elif subtext: 14 | caller = "%s - %s" % (caller, subtext) 15 | hbreak(0) 16 | hbox(caller, char=char) 17 | hbreak(0) 18 | 19 | 20 | def exit_error(msg="Exiting..."): 21 | """Exit the script in ERROR state with a positive status code.""" 22 | exit_as(1, 'error', msg=msg) 23 | 24 | 25 | def exit_info(msg="Exiting..."): 26 | """Exit the script in INFO state with a positive status code.""" 27 | exit_as(0, 'info', msg=msg) 28 | 29 | 30 | def exit_failed(msg="Exiting..."): 31 | """Exit the script in FAILED state with a positive status code.""" 32 | exit_as(1, 'failed', msg=msg) 33 | 34 | 35 | def exit_passed(msg="Exiting..."): 36 | """Exit the script in PASSED state with a zero status code.""" 37 | exit_as(0, 'passed', msg=msg) 38 | 39 | 40 | def exit_as(scode, sstring, msg=False, char='#'): 41 | """Exit the script as specified.""" 42 | if msg is False: 43 | sys.exit(scode) 44 | # Update the status string and decorative character. 45 | sstring = sstring.upper() 46 | if scode: 47 | char = '!' 48 | # Start rendering the output. 49 | hbreak() 50 | hline(char=char) 51 | if msg is None: 52 | hline(sstring, char=char) 53 | elif '\n' in msg: 54 | hline("%s:\n%s" % (sstring, msg), char=char) 55 | else: 56 | hline("%s - %s" % (sstring, msg), char=char) 57 | hline(char=char) 58 | sys.exit(scode) 59 | 60 | 61 | def hbox(text, char='.'): 62 | """Print a horizontal box with text.""" 63 | hline(char=char) 64 | hline(text, char=char) 65 | hline(char=char) 66 | 67 | 68 | def hbreak(lines=1): 69 | """Print newlines (two by default, just one with lines=0).""" 70 | print(lines * "\n") 71 | 72 | 73 | def hline(text='', mlen=95, char='-', lchar=None, rchar=None): 74 | """Print a horizontal line (with optional text).""" 75 | if not lchar: 76 | lchar = char 77 | if not rchar: 78 | rchar = char 79 | for index, line in enumerate(text.split('\n')): 80 | if line: 81 | line = ' ' + line + ' ' 82 | if index == 0: 83 | line_right = (mlen-2-len(line)) * rchar 84 | else: 85 | line_right = ((mlen-4-len(line)) * ' ') + rchar + rchar 86 | print(lchar + lchar + line + line_right) 87 | -------------------------------------------------------------------------------- /.travis/test_python_pep8_compliancy.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """Tests the PEP8 compliancy of all Python code.""" 4 | import subprocess 5 | import flow 6 | 7 | 8 | def _test_pep8(args): 9 | """Shell wrapper for Pylint/Pycodestyle calls.""" 10 | flow.hline("%s (%s)" % (args[1], args[0])) 11 | cmd = " ".join(args) 12 | proc = subprocess.run(cmd, 13 | stdout=subprocess.PIPE, 14 | stderr=subprocess.STDOUT, 15 | shell=True) 16 | proc_output = proc.stdout.decode("utf-8") + "\n" 17 | if proc.returncode == 127: 18 | print("Binary %s not found!" % args[0]) 19 | return False 20 | if args[0] == 'pylint': 21 | if proc.returncode != 0: 22 | print("cmd: %s (exit status: %d)\n" % (cmd, proc.returncode)) 23 | print(proc_output) 24 | 25 | # Scan and report pylint ignore tags. 26 | ignores = subprocess.run( 27 | "grep -r 'pylint:disable' %s|grep -v grep" % args[1], 28 | stdout=subprocess.PIPE, 29 | stderr=subprocess.DEVNULL, 30 | shell=True) 31 | ignores = ignores.stdout.decode("utf-8").strip() 32 | if ignores: 33 | flow.hline("Code-level linter ignores", char=".") 34 | print(ignores) 35 | return False 36 | else: 37 | if proc.returncode == 1: 38 | print("cmd: %s (exit status: %d)\n" % (cmd, proc.returncode)) 39 | print(proc_output) 40 | return False 41 | return True 42 | 43 | 44 | if __name__ == '__main__': 45 | flow.banner(__file__) 46 | TESTS = [] 47 | TESTS.append( 48 | _test_pep8(["pycodestyle", 49 | ".travis/", 50 | "--show-source"])) 51 | TESTS.append( 52 | _test_pep8(["pylint", 53 | ".travis/*.py", 54 | "--disable=duplicate-code", 55 | "--disable=no-value-for-parameter"])) 56 | TESTS.append( 57 | _test_pep8(["pycodestyle", 58 | "app", 59 | "--show-source", 60 | "--max-line-length=300"])) 61 | TESTS.append( 62 | _test_pep8(["pylint", 63 | "app", 64 | "--disable=line-too-long"])) 65 | if False in TESTS: 66 | flow.exit_failed(msg="Please fix the reported codestyle issues.") 67 | flow.exit_passed(msg="All code is PEP8 compliant!") 68 | -------------------------------------------------------------------------------- /app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | 3 | ARG DEBIAN_FRONTEND=noninteractive 4 | ARG USER=drucker 5 | ARG SSH=/home/"$USER"/.ssh 6 | 7 | VOLUME ["/data"] 8 | 9 | # Ensure we're up-to-date. 10 | RUN apt-get update -y && apt-get upgrade -y 11 | 12 | # Make sure dpkg works as intended. 13 | RUN apt-get install -y apt-utils 14 | 15 | # Packages needed for Ansible orchestration. 16 | RUN apt-get install -y \ 17 | ssh \ 18 | python-simplejson \ 19 | unzip \ 20 | sudo \ 21 | vim 22 | 23 | # Create a drucker sudoer. 24 | RUN adduser -q --disabled-password --gecos '' "$USER" \ 25 | && usermod -aG sudo "$USER" 26 | RUN echo "$USER":"$USER" | chpasswd 27 | 28 | # Prepare for SSH access 29 | RUN mkdir -p "$SSH" 30 | ENTRYPOINT service ssh restart && bash 31 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | """Initialization file for the drucker support library.""" 2 | from . import variables 3 | from . import arguments 4 | from . import requirements 5 | from . import local_setup 6 | from . import init 7 | from . import base 8 | from . import mirror 9 | from . import edge 10 | from . import db 11 | from . import search 12 | from . import web 13 | 14 | # Declare all submodules so that pydoc and others know how to find them. 15 | __all__ = [ 16 | "variables", 17 | "arguments", 18 | "requirements", 19 | "local_setup", 20 | "init", 21 | "base", 22 | "mirror", 23 | "edge", 24 | "db", 25 | "search", 26 | "web", 27 | ] 28 | -------------------------------------------------------------------------------- /app/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | retry_files_enabled = False 3 | allow_world_readable_tmpfiles = True 4 | 5 | [inventory] 6 | 7 | [privilege_escalation] 8 | 9 | [paramiko_connection] 10 | 11 | [ssh_connection] 12 | pipelining = True 13 | 14 | [persistent_connection] 15 | 16 | [accelerate] 17 | 18 | [selinux] 19 | 20 | [colors] 21 | 22 | [diff] 23 | -------------------------------------------------------------------------------- /app/base.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Manages the base image and container""" 3 | 4 | from datetime import date 5 | import subprocess 6 | import colorful 7 | from . import ssh 8 | from . import orchestration as o 9 | 10 | 11 | def create_base_container(drucker): 12 | """Create base container from init image""" 13 | print( 14 | colorful.white_on_blue( 15 | "Spinning up %s container with ID:" % (drucker.vars.BASE_CONTAINER) 16 | ) 17 | ) 18 | subprocess.run( 19 | "docker run -d --name %s -it --net %s --ip %s %s bash" 20 | % ( 21 | drucker.vars.BASE_CONTAINER, 22 | drucker.vars.APP, 23 | drucker.vars.BASE_IP, 24 | drucker.vars.INIT_IMAGE, 25 | ), 26 | shell=True, 27 | ) 28 | 29 | ssh.configure_ssh_base(drucker) 30 | o.run_base_orchestration(drucker) 31 | 32 | 33 | def create_base_image(drucker): 34 | """Create base image from base container""" 35 | print( 36 | colorful.white_on_blue( 37 | "Committing %s image from %s container..." 38 | % (drucker.vars.BASE_IMAGE, drucker.vars.BASE_CONTAINER) 39 | ) 40 | ) 41 | subprocess.run( 42 | 'docker commit -m "%s on %s" %s %s' 43 | % ( 44 | drucker.vars.BASE_CONTAINER, 45 | str(date.today()), 46 | drucker.vars.BASE_CONTAINER, 47 | drucker.vars.BASE_IMAGE, 48 | ), 49 | shell=True, 50 | ) 51 | 52 | 53 | def delete_base_container(drucker): 54 | """Delete base container""" 55 | print( 56 | colorful.white_on_blue( 57 | "Deleting %s container..." % (drucker.vars.BASE_CONTAINER) 58 | ) 59 | ) 60 | subprocess.getoutput( 61 | "docker rm -f %s > /dev/null 2>&1" % (drucker.vars.BASE_CONTAINER) 62 | ) 63 | 64 | 65 | def delete_init_image(drucker): 66 | """Delete init image""" 67 | print(colorful.white_on_blue("Deleting %s image..." % (drucker.vars.INIT_IMAGE))) 68 | subprocess.getoutput("docker rmi %s > /dev/null 2>&1" % (drucker.vars.INIT_IMAGE)) 69 | 70 | 71 | def provision_base_container(drucker): 72 | """Set up base container from init image""" 73 | if subprocess.getoutput(drucker.vars.CHECK_BASE_IMAGE): 74 | print(colorful.green("%s image already exists." % (drucker.vars.BASE_IMAGE))) 75 | 76 | if subprocess.getoutput(drucker.vars.CHECK_INIT_IMAGE): 77 | delete_init_image(drucker) 78 | else: 79 | if subprocess.getoutput( 80 | 'docker ps -a | grep -o "%s"' % (drucker.vars.BASE_CONTAINER) 81 | ): 82 | delete_base_container(drucker) 83 | else: 84 | create_base_container(drucker) 85 | create_base_image(drucker) 86 | delete_base_container(drucker) 87 | delete_init_image(drucker) 88 | 89 | 90 | def main(drucker): 91 | """Main dispatcher called by the main drucker script.""" 92 | provision_base_container(drucker) 93 | -------------------------------------------------------------------------------- /app/init.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Initialize app with Docker networking and init image""" 3 | 4 | import subprocess 5 | import colorful 6 | 7 | 8 | def create_bridge_network(drucker): 9 | """Creates a custom bridge network""" 10 | if subprocess.getoutput(drucker.vars.CHECK_BRIDGE): 11 | print( 12 | colorful.green( 13 | "Custom %s bridge network already exists." % (drucker.vars.APP) 14 | ) 15 | ) 16 | else: 17 | print( 18 | colorful.white_on_blue( 19 | "Creating custom %s bridge network..." % (drucker.vars.APP) 20 | ) 21 | ) 22 | subprocess.getoutput(drucker.vars.CREATE_BRIDGE) 23 | 24 | 25 | def pull_base_image(drucker): 26 | """Pulls and updates the preferred distribution image from the Docker Hub""" 27 | distro_image_exists = subprocess.getoutput(drucker.vars.CHECK_DISTRO_IMAGE) 28 | base_image_exists = subprocess.getoutput(drucker.vars.CHECK_BASE_IMAGE) 29 | 30 | if distro_image_exists and not base_image_exists: 31 | print(colorful.green("%s image already exists" % (drucker.vars.DISTRO_IMAGE))) 32 | print( 33 | colorful.white_on_blue( 34 | "Check if %s can be updated..." % (drucker.vars.DISTRO_IMAGE) 35 | ) 36 | ) 37 | subprocess.run(drucker.vars.UPDATE_DISTRO_IMAGE, shell=True) 38 | elif not distro_image_exists: 39 | print( 40 | colorful.white_on_blue( 41 | "Pulling %s image from Docker Hub..." % (drucker.vars.DISTRO_IMAGE) 42 | ) 43 | ) 44 | subprocess.run(drucker.vars.PULL_DISTRO_IMAGE, shell=True) 45 | 46 | 47 | def build_init_image(drucker): 48 | """Builds the init image from Dockerfile""" 49 | if subprocess.getoutput(drucker.vars.CHECK_INIT_IMAGE): 50 | print(colorful.green("%s image already exists." % (drucker.vars.INIT_IMAGE))) 51 | elif not subprocess.getoutput(drucker.vars.CHECK_BASE_IMAGE): 52 | print( 53 | colorful.white_on_blue( 54 | "Building %s image from Dockerfile..." % (drucker.vars.INIT_IMAGE) 55 | ) 56 | ) 57 | subprocess.run( 58 | 'docker build -t "%s" %s' % (drucker.vars.INIT_IMAGE, drucker.vars.APP_DIR), 59 | shell=True, 60 | ) 61 | 62 | 63 | def main(drucker): 64 | """Main dispatcher called by the main drucker script.""" 65 | create_bridge_network(drucker) 66 | pull_base_image(drucker) 67 | build_init_image(drucker) 68 | -------------------------------------------------------------------------------- /app/local_setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Edit the config file to accommodate for local user preferences""" 3 | 4 | import os 5 | import colorful 6 | 7 | 8 | def replace_string(file, old_string, new_string): 9 | """Allows to easily replace a string in a file""" 10 | with open(file) as target: 11 | replacement = target.read().replace(old_string, new_string) 12 | with open(file, "w") as target: 13 | target.write(replacement) 14 | 15 | 16 | def set_local_ssh_path(drucker): 17 | """Write the SSH public key path to the config file""" 18 | if drucker.vars.KEY_PLACEHOLDER in open(drucker.vars.DEFAULT_CONFIG).read(): 19 | pubkey = input( 20 | "Enter path to SSH public key (%s): " % (drucker.vars.DEFAULT_PUBKEY) 21 | ) 22 | 23 | if not pubkey: 24 | replace_string( 25 | drucker.vars.DEFAULT_CONFIG, 26 | drucker.vars.KEY_PLACEHOLDER, 27 | drucker.vars.DEFAULT_PUBKEY, 28 | ) 29 | elif os.path.isfile(pubkey): 30 | replace_string( 31 | drucker.vars.DEFAULT_CONFIG, drucker.vars.KEY_PLACEHOLDER, pubkey 32 | ) 33 | else: 34 | print(colorful.red("This filepath doesn't exist. Please try again.")) 35 | set_local_ssh_path(drucker) 36 | 37 | 38 | def set_local_html_path(drucker): 39 | """Write the local HTML path to the config file""" 40 | if drucker.vars.HTML_PLACEHOLDER in open(drucker.vars.DEFAULT_CONFIG).read(): 41 | host_html_path = input( 42 | """ 43 | Where should we store sites locally? (%s): """ 44 | % (drucker.vars.DEFAULT_HTML_PATH) 45 | ) 46 | 47 | if not host_html_path: 48 | replace_string( 49 | drucker.vars.DEFAULT_CONFIG, 50 | drucker.vars.HTML_PLACEHOLDER, 51 | drucker.vars.DEFAULT_HTML_PATH, 52 | ) 53 | elif os.path.isfile(host_html_path): 54 | replace_string( 55 | drucker.vars.DEFAULT_CONFIG, 56 | drucker.vars.HTML_PLACEHOLDER, 57 | host_html_path, 58 | ) 59 | else: 60 | print(colorful.red("This filepath doesn't exist. Please try again.")) 61 | set_local_html_path(drucker) 62 | 63 | 64 | def set_local_db_path(drucker): 65 | """Write the local DB path to the config file""" 66 | if drucker.vars.DB_PLACEHOLDER in open(drucker.vars.DEFAULT_CONFIG).read(): 67 | host_db_path = input( 68 | """ 69 | Where should we store databases locally? (%s): """ 70 | % (drucker.vars.DEFAULT_DB_PATH) 71 | ) 72 | 73 | if not host_db_path: 74 | replace_string( 75 | drucker.vars.DEFAULT_CONFIG, 76 | drucker.vars.DB_PLACEHOLDER, 77 | drucker.vars.DEFAULT_DB_PATH, 78 | ) 79 | elif os.path.isfile(host_db_path): 80 | replace_string( 81 | drucker.vars.DEFAULT_CONFIG, drucker.vars.DB_PLACEHOLDER, host_db_path 82 | ) 83 | else: 84 | print(colorful.red("This filepath doesn't exist. Please try again.")) 85 | set_local_db_path(drucker) 86 | 87 | 88 | def main(drucker): 89 | """Main dispatcher called by the main drucker script.""" 90 | set_local_ssh_path(drucker) 91 | set_local_html_path(drucker) 92 | set_local_db_path(drucker) 93 | -------------------------------------------------------------------------------- /app/orchestration/_tests/db-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_db 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-db-tests.yml 13 | -------------------------------------------------------------------------------- /app/orchestration/_tests/edge-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_edge 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-edge-tests.yml 13 | -------------------------------------------------------------------------------- /app/orchestration/_tests/mirror-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_mirror 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-mirror-tests.yml 13 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/db/adminer-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Adminer needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ adminer_root }}" 7 | - "{{ adminer_index }}" 8 | - "{{ adminer_vhost }}" 9 | register: adminer 10 | failed_when: adminer.stat.exists == false 11 | 12 | - name: "TEST: Adminer should be at the latest version" 13 | shell: grep -o "version {{ adminer_stable_release }}" {{ adminer_index }} || echo "update" 14 | register: adminer_release 15 | changed_when: adminer_release == "update" 16 | failed_when: adminer_release == "update" 17 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/db/db-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: MariaDB and utilities need to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ db_config }}" 7 | - "{{ db_data }}" 8 | - "{{ db_backup_path }}" 9 | register: mariadb_check 10 | failed_when: mariadb_check.stat.exists == false 11 | 12 | - name: "TEST: Check if MariaDB and utilities packages are installed" 13 | shell: dpkg -l | grep {{ item }} 14 | with_items: 15 | - mariadb-server 16 | - mysql-common 17 | - python-mysqldb 18 | - memcached 19 | register: mariadb_packages 20 | changed_when: mariadb_packages == '' 21 | 22 | - name: "TEST: Check if MariaDB innodb_file_per_table setting is configured" 23 | shell: grep -o "innodb_file_per_table = 1" {{ db_config }} || echo "missing" 24 | register: mariadb_innodb_setting 25 | changed_when: mariadb_innodb_setting.stdout == "missing" 26 | failed_when: mariadb_innodb_setting.stdout == "missing" 27 | 28 | - set_fact: 29 | db_dir_expected_ownership: "mysql:mysql" 30 | 31 | - name: "TEST: The database directory should have correct ownership" 32 | shell: stat -c %U:%G {{ db_data }} 33 | register: db_dir_ownership 34 | changed_when: db_dir_ownership.stdout != db_dir_expected_ownership 35 | failed_when: db_dir_ownership.stdout != db_dir_expected_ownership 36 | 37 | - name: "TEST: Check if MariaDB backup cron job exists" 38 | shell: crontab -l | grep -o "{{ db_backup_path }}" || echo "missing" 39 | register: mariadb_backup_cron 40 | changed_when: mariadb_backup_cron.stdout == "missing" 41 | failed_when: mariadb_backup_cron.stdout == "missing" 42 | 43 | - name: "TEST: Check if MariaDB backup cleanup cron job exists" 44 | shell: crontab -l | grep -o "mmin +180" || echo "missing" 45 | register: mariadb_cleanup_cron 46 | changed_when: mariadb_cleanup_cron.stdout == "missing" 47 | failed_when: mariadb_cleanup_cron.stdout == "missing" 48 | 49 | - name: "TEST: Check if MariaDB remote access is configured" 50 | shell: grep -o "0.0.0.0" {{ db_config }} || echo "denied" 51 | register: mariadb_remote_access 52 | changed_when: mariadb_remote_access.stdout == "denied" 53 | failed_when: mariadb_remote_access.stdout == "denied" 54 | 55 | - name: "TEST: MariaDB process needs to be started" 56 | command: pgrep mysqld 57 | register: mariadb_process 58 | changed_when: mariadb_process.stdout == "" 59 | failed_when: mariadb_process.stdout == "" 60 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/db/memcached-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Check if memcached is installed" 3 | shell: dpkg -l | grep {{ item }} 4 | with_items: 5 | - memcached 6 | register: memcached_package 7 | changed_when: memcached_package == '' 8 | 9 | - name: "TEST: memcached process needs to be started" 10 | command: pgrep memcached 11 | register: memcached_process 12 | changed_when: memcached_process.stdout == "" 13 | failed_when: memcached_process.stdout == "" 14 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/db/phpmyadmin-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: phpMyAdmin needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ phpmyadmin_vhost }}" 7 | - "{{ phpmyadmin_config }}" 8 | - "{{ phpmyadmin_release_date_file }}" 9 | register: pma 10 | failed_when: pma.stat.exists == false 11 | 12 | - name: "TEST: phpMyAdmin should use the latest stable release" 13 | stat: 14 | path: "{{ phpmyadmin_release_date_file }}" 15 | register: pma_version 16 | failed_when: pma_version.stat.exists == false 17 | 18 | - name: "TEST: The mariadb client should be installed" 19 | shell: dpkg -l | grep mariadb-client 20 | register: mariadb_client_package 21 | changed_when: mariadb_client_package == '' 22 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/drupal/drupal-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Drupal needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ drupal_root }}" 7 | - "{{ drupal_docroot }}/{{ default_site }}/settings.php" 8 | - "{{ drupal_docroot }}/{{ default_site }}/services.yml" 9 | - "{{ drupal_docroot }}/{{ sites_php }}" 10 | - "{{ drupal_root }}/{{ default_configuration_dir }}" 11 | - "{{ drupal_docroot }}" 12 | - "{{ files_dir }}" 13 | - "{{ libraries_dir }}" 14 | - "{{ settings_php }}" 15 | - "{{ services_yml }}" 16 | - "{{ simpletest_dir }}" 17 | - "{{ drupal_git }}" 18 | - "{{ drupal_gitignore }}" 19 | # - "{{ db_data }}/{{ user }}" 20 | - "{{ phpunit_xml }}" 21 | - "{{ import_dir }}" 22 | - "{{ archives_dir }}" 23 | - "{{ log_dir }}/{{ user }}-access.log" 24 | - "{{ log_dir }}/{{ user }}-error.log" 25 | register: drupal 26 | failed_when: drupal.stat.exists == false 27 | 28 | - name: "TEST: The config directory should have correct permissions" 29 | shell: stat -c -%a {{ drupal_root }}/{{ default_configuration_dir }} | tail -c5 30 | register: config_permissions 31 | changed_when: config_permissions.stdout != "2775" 32 | failed_when: config_permissions.stdout != "2775" 33 | 34 | - name: "TEST: settings.php should hold the correct trusted_host_patterns setting" 35 | shell: grep -F "{{ user }}\.{{ tld }}" {{ settings_php }} || echo "missing" 36 | register: trusted_host_patterns 37 | changed_when: trusted_host_patterns.stdout == "missing" 38 | failed_when: trusted_host_patterns.stdout == "missing" 39 | 40 | - set_fact: 41 | expected_ownership: "{{ user }}:{{ apache_user }}" 42 | 43 | - name: "TEST: The styles directory should have correct ownership" 44 | shell: stat -c %U:%G {{ files_dir }}/styles 45 | register: styles_dir_ownership 46 | changed_when: styles_dir_ownership.stdout != expected_ownership 47 | failed_when: styles_dir_ownership.stdout != expected_ownership 48 | 49 | - name: "TEST: Make sure the codebase was added under version control" 50 | shell: git -C {{ drupal_root }} log --oneline | grep -o "Initial commit" || echo 'no commit' 51 | args: 52 | warn: no 53 | register: initial_commit 54 | changed_when: initial_commit == "no commit" 55 | failed_when: initial_commit == "no commit" 56 | 57 | - name: "TEST: Ensure remote MySQL databases can be managed" 58 | shell: dpkg -l | grep "python-mysqldb" 59 | register: remote_db_management 60 | changed_when: remote_db_management == '' 61 | 62 | - name: "TEST: Ensure Drupal can talk to the Solr backend" 63 | shell: grep -o "{{ search_ip }}" {{ hosts_file }} || echo "absent" 64 | register: search_hostname_check 65 | changed_when: search_hostname_check == "absent" 66 | failed_when: search_hostname_check == "absent" 67 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/edge/mirror-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: APT mirror needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ mirror_cache_dir }}" 7 | - "{{ mirror_log_dir }}" 8 | register: mirror_installation 9 | failed_when: mirror_installation.stat.exists == false 10 | 11 | - name: "TEST: APT mirror web interface should be accessible" 12 | uri: 13 | url: "http://mirror.{{ tld }}:3142" 14 | status_code: 406 15 | 16 | - name: "TEST: Archives, directories and files should be accessible" 17 | stat: 18 | path: "{{ item }}" 19 | with_items: 20 | - "{{ mirror_archives_dir }}" 21 | - "{{ solr_mirror_archive_path }}" 22 | - "{{ libyaml_mirror_archive_path }}" 23 | - "{{ pecl_yaml_mirror_archive_path }}" 24 | - "{{ xdebug_mirror_archive_path }}" 25 | - "{{ tideways_mirror_archive_path }}" 26 | - "{{ phantomjs_mirror_archive_path }}" 27 | - "{{ phpcs_mirror_archive_path }}" 28 | - "{{ phpcbf_mirror_archive_path }}" 29 | - "{{ php_cs_fixer_mirror_archive_file }}" 30 | # - "{{ phpmd_mirror_archive_file }}" 31 | - "{{ mcstat_mirror_archive_file }}" 32 | - "{{ phpmyadmin_mirror_archive_file_path }}" 33 | - "{{ adminer_mirror_filepath }}" 34 | register: archive_elements 35 | failed_when: archive_elements.stat.exists == false 36 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/edge/nginx-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: nginx signing key should be installed" 3 | shell: apt-key list | grep -o "nginx signing key" || echo "no signing key" 4 | register: nginx_key 5 | changed_when: nginx_key == "no signing key" 6 | failed_when: nginx_key == "no signing key" 7 | 8 | - name: "TEST: nginx needs to be correctly installed" 9 | stat: 10 | path: "{{ item }}" 11 | with_items: 12 | - "{{ nginx_conf }}" 13 | - "{{ drucker_nginx_vhost }}" 14 | - "{{ nginx_conf_dir }}" 15 | register: nginx 16 | failed_when: nginx.stat.exists == false 17 | 18 | - name: "TEST: nginx default files should not exist" 19 | stat: 20 | path: "{{ item }}" 21 | with_items: 22 | - "{{ nginx_default_site }}" 23 | - "{{ nginx_default_conf }}" 24 | register: nginx_default_files 25 | failed_when: nginx_default_files.stat.exists == true 26 | 27 | - name: "TEST: Check if nginx package is installed" 28 | shell: dpkg -l | grep nginx 29 | register: nginx_package 30 | changed_when: nginx_package == '' 31 | 32 | - name: "TEST: nginx proxy_pass should be set" 33 | shell: grep -o "proxy_pass http://{{ web_ip }}:{{ edge_port }}" "{{ drucker_nginx_vhost }}" || echo "missing" 34 | register: nginx_proxy_pass 35 | changed_when: nginx_proxy_pass.stdout == "missing" 36 | failed_when: nginx_proxy_pass.stdout == "missing" 37 | 38 | - name: "TEST: nginx process needs to be started" 39 | command: pgrep nginx 40 | register: nginx_process 41 | changed_when: nginx_process.stdout == "" 42 | failed_when: nginx_process.stdout == "" 43 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/edge/varnish-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Varnish needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ varnish_config }}" 7 | - "{{ varnish_default_path }}" 8 | - "{{ varnish_default_vcl }}" 9 | register: varnish 10 | failed_when: varnish.stat.exists == false 11 | 12 | - name: "TEST: Check if Varnish package is installed" 13 | shell: dpkg -l | grep {{ item }} 14 | with_items: 15 | - varnish 16 | register: varnish_packages 17 | changed_when: varnish_packages == '' 18 | 19 | - name: "TEST: Varnish should listen on port 80" 20 | shell: grep -o "{{ edge_port }}" {{ varnish_config }} || || echo "wrong port" 21 | register: varnish_port_check 22 | changed_when: varnish_port_check.stdout == "wrong port" 23 | failed_when: varnish_port_check.stdout == "wrong port" 24 | 25 | - name: "TEST: Varnish process needs to be started" 26 | command: pgrep varnishd 27 | register: varnishd_process 28 | changed_when: varnishd_process.stdout == "" 29 | failed_when: varnishd_process.stdout == "" 30 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/php/apache-common-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Apache needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ apache_security_conf }}" 7 | - "{{ apache_actions_mod }}" 8 | - "{{ apache_rewrite_mod }}" 9 | - "{{ apache_proxy_http_mod }}" 10 | register: apache 11 | failed_when: apache.stat.exists == false 12 | 13 | - name: "TEST: The POODLE SSL v3 vulnerability should be fixed" 14 | shell: grep -o "SSLProtocol all -SSLv2 -SSLv3" {{ apache_ssl_mod }} || echo "absent" 15 | register: poodle 16 | changed_when: poodle.stdout == "absent" 17 | failed_when: poodle.stdout == "absent" 18 | 19 | - name: "TEST: apache2 process needs to be started" 20 | command: pgrep apache2 21 | register: apache2_process 22 | changed_when: apache2_process.stdout == "" 23 | failed_when: apache2_process.stdout == "" 24 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/php/apache-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_tasks: apache-common-tests.yml 3 | 4 | - name: "TEST: Check if Apache and web tools are installed" 5 | shell: dpkg -l | grep {{ item }} 6 | with_items: 7 | - apache2 8 | - apache2-utils 9 | - goaccess 10 | register: apache_packages 11 | changed_when: apache_packages == '' 12 | 13 | - name: "TEST: APACHE_RUN_USER should be set" 14 | shell: grep -o "export APACHE_RUN_USER={{ user }}" {{ apache_envvars }} || echo "absent" 15 | register: apache_run_user 16 | changed_when: apache_run_user.stdout == "absent" 17 | failed_when: apache_run_user.stdout == "absent" 18 | 19 | - name: "TEST: Web server group should be added to the drucker user" 20 | shell: groups {{ user }} | awk '{print $NF}' 21 | register: group_check 22 | changed_when: group_check.stdout != apache_user 23 | failed_when: group_check.stdout != apache_user 24 | 25 | - name: "TEST: Permissions should be correct in the webroot" 26 | shell: stat -c %U:%G "{{ item }}" | grep "{{ user }}:{{ apache_user }}" || echo "Wrong permissions" 27 | with_items: 28 | - "{{ adminer_root }}" 29 | - "{{ phpmyadmin_root }}" 30 | - "{{ import_dir }}" 31 | register: webroot_permissions 32 | changed_when: webroot_permissions.stdout == "Wrong permissions" 33 | failed_when: webroot_permissions.stdout == "Wrong permissions" 34 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/php/pecl-yaml-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: PECL YAML needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ pecl_yaml_extension_path }}" 7 | - "{{ pecl_yaml_archive }}" 8 | - "{{ libyaml_archive_path }}" 9 | register: pecl_yaml 10 | failed_when: pecl_yaml.stat.exists == false 11 | 12 | - name: "TEST: PECL YAML should be configured in php.ini" 13 | shell: grep -o "{{ pecl_yaml_extension_name }}" {{ default_php_ini }} || echo "absent" 14 | register: pecl_yaml_phpini 15 | changed_when: pecl_yaml_phpini == "absent" 16 | failed_when: pecl_yaml_phpini == "absent" 17 | 18 | - name: "TEST: Temporary C YAML parser directory should not exist" 19 | stat: 20 | path: "{{ libyaml_temp_path }}" 21 | register: pecl_yaml_temp_dir 22 | failed_when: pecl_yaml_temp_dir.stat.exists == true 23 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/php/php-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Check if PHP is installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ default_php_ini }}" 7 | - "{{ default_php_ini_cli }}" 8 | - "{{ apache_proxy_fcgi_mod }}" 9 | - "{{ default_php_extensions }}" 10 | register: php 11 | 12 | - name: "TEST: Check if PHP packages are installed" 13 | shell: dpkg -l | grep {{ item }} 14 | with_items: 15 | - php-apcu 16 | - php-imagick 17 | - php-memcached 18 | - php{{ default_php_version }}-fpm 19 | - php{{ default_php_version }}-cli 20 | - php{{ default_php_version }}-common 21 | - php{{ default_php_version }}-dev 22 | - php{{ default_php_version }}-curl 23 | - php{{ default_php_version }}-gd 24 | - php{{ default_php_version }}-mbstring 25 | - php{{ default_php_version }}-mysql 26 | - php{{ default_php_version }}-xmlrpc 27 | - php{{ default_php_version }}-xsl 28 | - php{{ default_php_version }}-bz2 29 | - php{{ default_php_version }}-sqlite3 30 | register: php_packages 31 | changed_when: php_packages == '' 32 | 33 | - name: "TEST: Apache's mod_proxy_fcgi needs to be correctly enabled" 34 | stat: 35 | path: "{{ apache_proxy_http_mod }}" 36 | register: apache_proxy_http_mod_check 37 | failed_when: apache_proxy_http_mod_check.stat.exists == false 38 | 39 | - name: "TEST: Apache vHosts need to support php-fpm Fast-CGI" 40 | shell: grep -o "ProxyPassMatch" "{{ sites_enabled }}/{{ sitename }}.conf" || echo "absent" 41 | register: proxypassmatch_conf 42 | changed_when: proxypassmatch_conf.stdout == "absent" 43 | failed_when: proxypassmatch_conf.stdout == "absent" 44 | 45 | - name: "TEST: Check php.ini's custom configuration" 46 | shell: grep -o "{{ item }}" {{ default_php_ini }} || echo "absent" 47 | with_items: 48 | - max_input_time = {{ max_input_time }} 49 | - max_execution_time = {{ max_execution_time }} 50 | - memory_limit = {{ memory_limit }} 51 | - upload_max_filesize = {{ upload_max_filesize }} 52 | - max_file_uploads = {{ max_file_uploads }} 53 | - post_max_size = {{ post_max_size }} 54 | - zend.assertions = -1 55 | - display_errors = Off 56 | register: php_ini_conf 57 | changed_when: php_ini_conf.stdout == "absent" 58 | failed_when: php_ini_conf.stdout == "absent" 59 | 60 | - name: "TEST: Check php.ini CLI's custom configuration" 61 | shell: grep -o "{{ item }}" {{ default_php_ini_cli }} || echo "absent" 62 | with_items: 63 | - date.timezone = {{ timezone }} 64 | register: php_ini_cli_conf 65 | changed_when: php_ini_cli_conf.stdout == "absent" 66 | failed_when: php_ini_cli_conf.stdout == "absent" 67 | 68 | - name: "TEST: APCu is expected to run the latest stable version" 69 | shell: php -r '$version = phpversion("apcu"); echo $version;' 70 | register: apcu_version 71 | changed_when: apcu_version.stdout != apcu_stable_release 72 | failed_when: apcu_version.stdout != apcu_stable_release 73 | 74 | - name: "TEST: php-memcached is expected to run the latest stable version" 75 | shell: dpkg -l | grep php-memcached | awk '{print $3}' | cut -c1-5 76 | register: memcached_version_check 77 | changed_when: memcached_version_check.stdout != php_memcached_stable_release 78 | failed_when: memcached_version_check.stdout != php_memcached_stable_release 79 | 80 | - name: "TEST: php-fpm process needs to be started" 81 | command: pgrep {{ php_process }} 82 | register: php_fpm_process 83 | changed_when: php_fpm_process.stdout == "" 84 | failed_when: php_fpm_process.stdout == "" 85 | 86 | - name: "TEST: All URLs should be accessible" 87 | uri: 88 | url: "{{ item }}" 89 | with_items: 90 | - http://{{ user }}.{{ tld }} 91 | - http://search.{{ tld }}:{{ solr_port }}/solr/# 92 | - http://phpmyadmin.{{ tld }} 93 | - http://adminer.{{ tld }} 94 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-db-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/db/db-tests.yml 2 | - import_tasks: plays/db/memcached-tests.yml 3 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-edge-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/edge/varnish-tests.yml 2 | - import_tasks: plays/edge/nginx-tests.yml 3 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-mirror-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/edge/mirror-tests.yml 2 | - import_tasks: plays/php/apache-common-tests.yml 3 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-search-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/solr/solr-configuration-tests.yml 2 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-system-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/system/system-setup-tests.yml 2 | - import_tasks: plays/system/git-tests.yml 3 | - import_tasks: plays/system/ssh-keys-tests.yml 4 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/run-web-tests.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: plays/php/apache-tests.yml 2 | - import_tasks: plays/php/php-tests.yml 3 | - import_tasks: plays/tools/composer-tests.yml 4 | - import_tasks: plays/db/phpmyadmin-tests.yml 5 | - import_tasks: plays/db/adminer-tests.yml 6 | - import_tasks: plays/tools/drush-tests.yml 7 | - import_tasks: plays/tools/drupal-console-tests.yml 8 | - import_tasks: plays/php/pecl-yaml-tests.yml 9 | - import_tasks: plays/tools/xdebug-tests.yml 10 | - import_tasks: plays/tools/tideways-tests.yml 11 | - import_tasks: plays/tools/phantomjs-tests.yml 12 | - import_tasks: plays/tools/codesniffer-tests.yml 13 | - import_tasks: plays/tools/php-cs-fixer-tests.yml 14 | - import_tasks: plays/tools/coder-tests.yml 15 | # - import_tasks: plays/tools/phpmd-tests.yml 16 | - import_tasks: plays/tools/mcstat-tests.yml 17 | - import_tasks: plays/drupal/drupal-tests.yml 18 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/solr/solr-configuration-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Check that all Apache Solr configuration files exist" 3 | stat: 4 | path: "{{ solr_configuration_path }}/{{ item }}" 5 | with_items: 6 | - elevate.xml 7 | - mapping-ISOLatin1Accent.txt 8 | - protwords.txt 9 | - schema.xml 10 | - schema_extra_fields.xml 11 | - schema_extra_types.xml 12 | - solrconfig.xml 13 | - solrconfig_spellcheck.xml 14 | - solrcore.properties 15 | - stopwords.txt 16 | - synonyms.txt 17 | register: solr_conf_files_check 18 | failed_when: solr_conf_files_check.stat.exists == false 19 | 20 | - name: "TEST: Apache Solr schema must be tuned for search_api_solr" 21 | shell: grep -o "search_api_solr" {{ solr_configuration_path }}/schema.xml | head -n1 || echo "missing" 22 | register: solr_conf_files_check 23 | changed_when: solr_conf_files_check.stdout == "missing" 24 | failed_when: solr_conf_files_check.stdout == "missing" 25 | 26 | - name: "TEST: Make sure Apache Solr server is running" 27 | shell: "{{ solr_binary }} status | grep 'running on port {{ solr_port }}' || echo 'not running'" 28 | register: solr_status 29 | changed_when: solr_status.stdout == "not running" 30 | failed_when: solr_status.stdout == "not running" 31 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/system/git-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Git needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ git_completion }}" 7 | - "{{ git_prompt }}" 8 | - "{{ bash_git_prompt }}" 9 | - "{{ git_config }}" 10 | - "{{ global_gitignore }}" 11 | - "{{ bash_git_prompt_archive_path }}" 12 | register: git 13 | failed_when: git.stat.exists == false 14 | 15 | - name: "TEST: Check if Git has been configured in .bashrc" 16 | shell: grep -o 'MANAGED GIT BLOCK' {{ bashrc }} || echo "absent" 17 | register: git_bashrc 18 | changed_when: git_bashrc.stdout == "absent" 19 | failed_when: git_bashrc.stdout == "absent" 20 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/system/ssh-keys-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: SSH keys needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ id_rsa }}" 7 | - "{{ id_rsa_pub }}" 8 | register: ssh_keys 9 | failed_when: ssh_keys.stat.exists == false 10 | 11 | - name: "TEST: Public SSH key needs to have 4096 bits" 12 | shell: ssh-keygen -l -f {{ id_rsa_pub }} | awk '{print $1}' 13 | register: ssh_bits 14 | changed_when: ssh_bits.stdout != "4096" 15 | failed_when: ssh_bits.stdout != "4096" 16 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/system/system-setup-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: System needs to be cleaned up" 3 | shell: dpkg -l | grep vim-tiny || echo "absent" 4 | register: system_cleanup 5 | changed_when: system_cleanup.stdout != 'absent' 6 | failed_when: system_cleanup.stdout != 'absent' 7 | 8 | - name: "TEST: System files need to be correctly installed" 9 | stat: 10 | path: "{{ item }}" 11 | with_items: 12 | - "{{ bash_aliases }}" 13 | - "{{ sudo_tty_workaround_file }}" 14 | register: system 15 | failed_when: system.stat.exists == false 16 | 17 | - name: "TEST: sources.list file needs to be correctly configured" 18 | shell: grep -o -m1 "{{ codename }} main contrib non-free" {{ sources_list }} || echo "absent" 19 | register: sources_list_repos 20 | changed_when: sources_list_repos.stdout == 'absent' 21 | failed_when: sources_list_repos.stdout == 'absent' 22 | 23 | - name: "TEST: System packages need to be correctly installed" 24 | shell: dpkg -l | grep {{ item }} 25 | with_items: 26 | - aptitude 27 | - ack-grep 28 | - apt-transport-https 29 | - curl 30 | - dstat 31 | - exuberant-ctags 32 | - git 33 | - htop 34 | - iputils-ping 35 | - libfontconfig1 36 | - logrotate 37 | - lsof 38 | - ncdu 39 | - netcat 40 | - net-tools 41 | - ntp 42 | - patchutils 43 | - silversearcher-ag 44 | - strace 45 | - sysstat 46 | - telnet 47 | - tcpdump 48 | - time 49 | - neovim 50 | - wget 51 | - xterm 52 | register: system_packages 53 | changed_when: system_packages == '' 54 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/coder-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Coder needs to be correctly installed" 3 | stat: 4 | path: "{{ coder_binary }}" 5 | register: coder 6 | failed_when: coder.stat.exists == false 7 | 8 | - name: "TEST: Coder should use the latest stable release" 9 | shell: grep -o "{{ coder_stable_release }}" {{ composer_json_path }} || echo "absent" 10 | register: coder_stable 11 | changed_when: coder_stable.stdout == "absent" 12 | failed_when: coder_stable.stdout == "absent" 13 | 14 | - name: "TEST: Check if Coder has been configured in .bashrc" 15 | shell: grep -o 'MANAGED CODE SNIFFER BLOCK' {{ bashrc }} || echo "absent" 16 | register: coder_bashrc 17 | changed_when: coder_bashrc.stdout == "absent" 18 | failed_when: coder_bashrc.stdout == "absent" 19 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/codesniffer-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: CodeSniffer needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ phpcs_binary }}" 7 | - "{{ phpcbf_binary }}" 8 | register: xdebug_install 9 | failed_when: xdebug_install.stat.exists == false 10 | 11 | - name: "TEST: CodeSniffer phpcs should use the latest stable release" 12 | shell: phpcs --version | awk '{print $3}' 13 | register: phpcs_version_check 14 | changed_when: phpcs_version_check.stdout != phpcs_stable_release 15 | failed_when: phpcs_version_check.stdout != phpcs_stable_release 16 | ignore_errors: true 17 | 18 | - name: "TEST: CodeSniffer phpcbf should use the latest stable release" 19 | shell: phpcbf --version | awk '{print $3}' 20 | register: phpcbf_version_check 21 | changed_when: phpcbf_version_check.stdout != phpcbf_stable_release 22 | failed_when: phpcbf_version_check.stdout != phpcbf_stable_release 23 | ignore_errors: true 24 | 25 | - name: "TEST: The CodeSniffer phpcs binary should be executable" 26 | stat: 27 | path: "{{ phpcs_binary }}" 28 | register: executable_phpcs 29 | 30 | - name: "TEST: The CodeSniffer phpcs binary should be executable" 31 | fail: 32 | msg: "The CodeSniffer phpcs binary isn't executable" 33 | when: executable_phpcs.stat.mode != "0755" 34 | 35 | - name: "TEST: The CodeSniffer phpcbf binary should be executable" 36 | stat: 37 | path: "{{ phpcbf_binary }}" 38 | register: executable_phpcbf 39 | 40 | - name: "TEST: The CodeSniffer phpcbf binary should be executable" 41 | fail: 42 | msg: "The CodeSniffer phpcbf binary isn't executable" 43 | when: executable_phpcbf.stat.mode != "0755" 44 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/composer-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Composer needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ composer_dir_path }}" 7 | - "{{ composer_dir_path }}/vendor" 8 | - "{{ composer_json_path }}" 9 | - "{{ composer_binary }}" 10 | register: composer 11 | failed_when: composer.stat.exists == false 12 | 13 | - name: "TEST: The composer binary should be executable" 14 | stat: 15 | path: "{{ composer_binary }}" 16 | register: executable_composer 17 | 18 | - name: "TEST: The Composer binary isn't executable" 19 | fail: 20 | msg: "The Composer binary isn't executable" 21 | when: executable_composer.stat.mode != "0755" 22 | 23 | - name: "TEST: Composer should use the latest stable release" 24 | shell: composer --version | awk '{print $3}' 25 | register: composer_version 26 | become: yes 27 | become_user: "{{ user }}" 28 | changed_when: composer_version.stdout != composer_stable_release 29 | failed_when: composer_version.stdout != composer_stable_release 30 | 31 | - name: "TEST: Composer should be in the $PATH" 32 | shell: grep -o "export PATH=\"\$PATH:\$HOME/.composer/vendor/bin\"" {{ bashrc }} || echo "absent" 33 | register: composer_path 34 | changed_when: composer_path.stdout == "absent" 35 | failed_when: composer_path.stdout == "absent" 36 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/drupal-console-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Drupal Console needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ drupal_console_binary }}" 7 | register: drupal_console 8 | failed_when: drupal_console.stat.exists == false 9 | 10 | - name: "TEST: Drupal Console Launcher should use the latest stable release" 11 | shell: drupal --version | head -n1 | awk '{print $NF}' 12 | register: drupal_console_launcher_version 13 | changed_when: drupal_console_launcher_version.stdout != drupal_console_launcher_stable_release 14 | failed_when: drupal_console_launcher_version.stdout != drupal_console_launcher_stable_release 15 | 16 | - name: "TEST: Check if Drupal Console has been configured in .bashrc" 17 | shell: grep -o "source \"\$HOME/.console/console.rc\" 2>/dev/null" {{ bashrc }} || echo "absent" 18 | register: drupal_console_bashrc 19 | changed_when: drupal_console_bashrc == "absent" 20 | failed_when: drupal_console_bashrc == "absent" 21 | 22 | - name: "TEST: Check if Drupal Console can connect to the drucker database" 23 | shell: drupal database:connect --root={{ drupal_docroot }} | grep -o "{{ user }}" || echo "Cannot connect to the database" 24 | register: drupal_console_db_connection 25 | changed_when: drupal_console_db_connection.stdout == "Cannot connect to the database" 26 | failed_when: drupal_console_db_connection.stdout == "Cannot connect to the database" 27 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/drush-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Drush needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ drush_launcher }}" 7 | - "{{ global_drush }}" 8 | - "{{ drush_alias_path }}" 9 | - "{{ drush_dir }}" 10 | register: drush 11 | failed_when: drush.stat.exists == false 12 | 13 | - name: "TEST: Drush Launcher should use the latest stable release" 14 | shell: drush --root={{ webroot }}/{{ user }} --version | head -n1 | awk '{print $NF}' 15 | register: drush_launcher_version_check 16 | changed_when: drush_launcher_version_check.stdout != drush_launcher_stable_release 17 | failed_when: drush_launcher_version_check.stdout != drush_launcher_stable_release 18 | 19 | - name: "TEST: Global Drush should use the latest stable release" 20 | shell: drush --root={{ webroot }}/{{ user }} --version | tail -n1 | awk '{print $NF}' 21 | register: global_drush_version_check 22 | changed_when: global_drush_version_check.stdout != global_drush_stable_release 23 | failed_when: global_drush_version_check.stdout != global_drush_stable_release 24 | 25 | - name: "TEST: Check if Drush can connect to the drucker database" 26 | shell: drush --root={{ webroot }}/{{ user }} sql-connect | grep -o "{{ user }}" || echo "Cannot connect to the database" 27 | register: drush_db_connection 28 | changed_when: drush_db_connection.stdout == "Cannot connect to the database" 29 | failed_when: drush_db_connection.stdout == "Cannot connect to the database" 30 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/mcstat-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: mcstat needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ mcstat_binary }}" 7 | - "{{ user_programs_path }}/{{ mcstat_unarchived_directory }}" 8 | register: mcstat_check 9 | failed_when: mcstat_check.stat.exists == false 10 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/phantomjs-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: PhantomJS needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ phantomjs_binary }}" 7 | register: phantomjs 8 | failed_when: phantomjs.stat.exists == false 9 | 10 | - name: "TEST: The phantomjs binary should be executable" 11 | stat: 12 | path: "{{ phantomjs_binary }}" 13 | register: executable_phantomjs 14 | 15 | - name: "TEST: The phantomjs binary isn't executable" 16 | fail: 17 | msg: "The phantomjs binary isn't executable" 18 | when: executable_phantomjs.stat.mode != "0755" 19 | 20 | - name: "TEST: The path to generate HTML files should be valid" 21 | shell: grep -o "{{ simpletest_dir }}" {{ phpunit_xml }} || echo "incorrect" 22 | register: phpunit_html_export_dir 23 | changed_when: phpunit_html_export_dir.stdout == "incorrect" 24 | failed_when: phpunit_html_export_dir.stdout == "incorrect" 25 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/php-cs-fixer-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: php-cs-fixer needs to be correctly installed" 3 | stat: 4 | path: "{{ php_cs_fixer_binary }}" 5 | register: php_cs_fixer 6 | failed_when: php_cs_fixer.stat.exists == false 7 | 8 | - name: "TEST: php-cs-fixer should use the latest stable release" 9 | shell: php-cs-fixer --version | awk '{print $5}' 10 | register: php_cs_fixer_version_check 11 | changed_when: php_cs_fixer_version_check.stdout != php_cs_fixer_stable_release 12 | failed_when: php_cs_fixer_version_check.stdout != php_cs_fixer_stable_release 13 | ignore_errors: true 14 | 15 | - name: "TEST: The php-cs-fixer binary should be executable" 16 | stat: 17 | path: "{{ php_cs_fixer_binary }}" 18 | register: executable_php_cs_fixer 19 | 20 | - name: "TEST: The php-cs-fixer binary isn't executable" 21 | fail: 22 | msg: "The php-cs-fixer binary isn't executable" 23 | when: executable_php_cs_fixer.stat.mode != "0755" 24 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/phpmd-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: phpmd needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ user_programs_path }}/phpmd" 7 | register: phpmd 8 | failed_when: phpmd.stat.exists == false 9 | 10 | - name: "TEST: phpmd should use the latest stable release" 11 | shell: phpmd --version | awk '{print $NF}' 12 | register: phpmd_version_check 13 | changed_when: phpmd_version_check.stdout != phpmd_stable_version 14 | failed_when: phpmd_version_check.stdout != phpmd_stable_version 15 | ignore_errors: true 16 | 17 | - name: "TEST: The phpmd binary should be executable" 18 | stat: 19 | path: "{{ user_programs_path }}/phpmd" 20 | register: executable_phpmd 21 | 22 | - name: "TEST: The phpmd binary isn't executable" 23 | fail: 24 | msg: "The phpmd binary isn't executable" 25 | when: executable_phpmd.stat.mode != "0755" 26 | 27 | - name: "TEST: Check if Coder has been configured in .bashrc" 28 | shell: grep -o 'MANAGED PHPMD BLOCK' {{ bashrc }} || echo "absent" 29 | register: phpmd_bashrc 30 | changed_when: phpmd_bashrc.stdout == "absent" 31 | failed_when: phpmd_bashrc.stdout == "absent" 32 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/tideways-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Tideways needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ tideways_extension_path }}" 7 | - "{{ tideways_archive }}" 8 | - "{{ tideways_output_dir }}" 9 | register: tideways 10 | failed_when: tideways.stat.exists == false 11 | 12 | - name: "TEST: Tideways should use the latest stable release" 13 | shell: php -c {{ default_php_ini }} -i | grep 'tideways' | grep -o '{{ tideways_stable_release }}' || echo 'update' 14 | register: tideways_version_check 15 | changed_when: tideways_version_check.stdout == "update" 16 | failed_when: tideways_version_check.stdout == "update" 17 | 18 | - name: "TEST: Tideways should be configured in php.ini" 19 | shell: grep -o "{{ tideways_extension_name }}" {{ default_php_ini }} || echo "absent" 20 | register: tideways_phpini 21 | changed_when: tideways_phpini == "absent" 22 | failed_when: tideways_phpini == "absent" 23 | 24 | - name: "TEST: The Tideways output directory should be writable" 25 | stat: 26 | path: "{{ tideways_output_dir }}" 27 | register: writable_tideways 28 | 29 | - name: "TEST: The Tideways output directory should be writable" 30 | fail: 31 | msg: "The Tideways output directory isn't writable" 32 | when: writable_tideways.stat.mode != "0777" 33 | -------------------------------------------------------------------------------- /app/orchestration/_tests/plays/tools/xdebug-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TEST: Xdebug needs to be correctly installed" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ xdebug_extension_path }}" 7 | - "{{ xdebug_archive_path }}" 8 | register: xdebug_install 9 | failed_when: xdebug_install.stat.exists == false 10 | 11 | - name: "TEST: Xdebug should be configured in php.ini" 12 | shell: grep -o "{{ xdebug_extension_name }}" {{ default_php_ini }} || echo "absent" 13 | register: xdebug_phpini 14 | changed_when: xdebug_phpini == "absent" 15 | failed_when: xdebug_phpini == "absent" 16 | 17 | - name: "TEST: Xdebug should use the latest release" 18 | shell: php -c {{ default_php_ini }} -i | grep -m1 -o {{ xdebug_stable_release }} || "absent" 19 | register: xdebug_phpini_version 20 | changed_when: xdebug_phpini_version == "absent" 21 | failed_when: xdebug_phpini_version == "absent" 22 | -------------------------------------------------------------------------------- /app/orchestration/_tests/search-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_search 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-search-tests.yml 13 | -------------------------------------------------------------------------------- /app/orchestration/_tests/system-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_web 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-system-tests.yml 13 | -------------------------------------------------------------------------------- /app/orchestration/_tests/web-tests.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Invoked via run_tests() in containers/orchestration. 3 | - hosts: drucker_web 4 | become: yes 5 | 6 | gather_facts: yes 7 | vars_files: 8 | - ../vars.yml 9 | handlers: 10 | - import_tasks: ../handlers.yml 11 | tasks: 12 | - import_tasks: plays/run-web-tests.yml 13 | vars: 14 | sitename: "drucker" 15 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-blt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/blt.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-delete.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/delete.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-dev.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/dev.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-drupal.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/drupal.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-import.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/import.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-lightning.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/lightning.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/app-prod.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/app/prod.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/default-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/php/default-php.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/legacy-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/php/legacy-php.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/commands/previous-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/php/previous-php.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/files/.bash_aliases: -------------------------------------------------------------------------------- 1 | # System 2 | alias ll='ls -lh --color=auto' 3 | alias la='ls -lhA --color=auto' 4 | alias grep='grep --color=auto' 5 | alias fgrep='fgrep --color=auto' 6 | alias egrep='egrep --color=auto' 7 | 8 | # VIM 9 | alias vi='vim' 10 | alias tags="/usr/bin/ctags --exclude=.git --exclude='*.css' --exclude='*.js' -R" 11 | -------------------------------------------------------------------------------- /app/orchestration/files/.gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | name = drucker 3 | email = drucker@drucker.local 4 | [core] 5 | autocrlf = false 6 | safecrlf = false 7 | ignorecase = false 8 | excludesfile = ~/.gitignore 9 | [color] 10 | ui = true 11 | [push] 12 | default = current 13 | [diff] 14 | renames = copies 15 | [alias] 16 | apply = apply --index -v 17 | p = format-patch --stdout 18 | diff = diff --full-index --binary 19 | co = checkout 20 | st = status --untracked-files=all 21 | unstash = !git stash show -p | git apply -R 22 | hist = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)[%an]%Creset' --abbrev-commit 23 | clean = clean -fdx 24 | reset = reset --hard 25 | -------------------------------------------------------------------------------- /app/orchestration/files/.gitignore: -------------------------------------------------------------------------------- 1 | docroot/sites/*/files 2 | docroot/sites/*/private 3 | docroot/sites/simpletest/* 4 | -------------------------------------------------------------------------------- /app/orchestration/files/.gitignore-global: -------------------------------------------------------------------------------- 1 | ###################### 2 | # OS generated files # 3 | ###################### 4 | ehthumbs.db 5 | Icon? 6 | Thumbs.db 7 | ._* 8 | .DS* 9 | .project 10 | *.lnk 11 | tmp* 12 | 13 | ############ 14 | # Packages # 15 | ############ 16 | *.7z 17 | *.dmg 18 | *.gz 19 | *.iso 20 | *.jar 21 | *.rar 22 | *.tar 23 | *.zip 24 | 25 | ###################### 26 | # Logs and databases # 27 | ###################### 28 | *.log 29 | *.sql 30 | 31 | ###################### 32 | # Vim generated files # 33 | ###################### 34 | *.un~ 35 | *.swp 36 | 37 | ########## 38 | # SASS # 39 | ########## 40 | .sass-cache 41 | 42 | ######################## 43 | # Patch/diff artifacts # 44 | ######################## 45 | *.patch 46 | *.diff 47 | *.orig 48 | *.rej 49 | interdiff*.txt 50 | 51 | ################### 52 | # emacs artifacts # 53 | ################### 54 | *~ 55 | \#*\# 56 | 57 | ######## 58 | # IDEs # 59 | ######## 60 | nbproject 61 | .idea 62 | 63 | ########## 64 | # Drupal # 65 | ########## 66 | ~/Sites/git/drupal/drupal/vendor 67 | -------------------------------------------------------------------------------- /app/orchestration/files/README-import.txt: -------------------------------------------------------------------------------- 1 | Read more at https://github.com/anavarre/drucker/wiki/Importing-an-existing-site-to-drucker 2 | -------------------------------------------------------------------------------- /app/orchestration/files/apache-template.conf: -------------------------------------------------------------------------------- 1 | 2 | 3 | ServerName SITENAME.local 4 | ServerAlias SITENAME.local 5 | ServerAdmin admin@SITENAME.local 6 | DocumentRoot /var/www/html/SITENAME/docroot 7 | 8 | 9 | Options Indexes FollowSymLinks 10 | AllowOverride All 11 | Require all granted 12 | 13 | 14 | ErrorLog ${APACHE_LOG_DIR}/SITENAME-error.log 15 | CustomLog ${APACHE_LOG_DIR}/SITENAME-access.log combined 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/orchestration/files/apt.conf: -------------------------------------------------------------------------------- 1 | Acquire::http { Proxy "http://HOST:PORT"; }; 2 | -------------------------------------------------------------------------------- /app/orchestration/files/composer-dev-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anavarre/drucker", 3 | "description": "drucker build.", 4 | "type": "project", 5 | "license": "GPL-2.0-or-later", 6 | "minimum-stability": "dev", 7 | "prefer-stable": true, 8 | "repositories": [ 9 | { 10 | "type": "composer", 11 | "url": "https://packages.drupal.org/8" 12 | }, 13 | { 14 | "type": "composer", 15 | "url": "https://asset-packagist.org" 16 | } 17 | ], 18 | "require": { 19 | "composer/installers": "^1.5", 20 | "drupal-composer/drupal-scaffold": "^2.4", 21 | "cweagans/composer-patches": "^1.6", 22 | "drupal/core": "^8.7", 23 | "drush/drush": "^9.0", 24 | "drupal/console": "^1.0" 25 | }, 26 | "require-dev": { 27 | "behat/mink": "1.7.x-dev", 28 | "behat/mink-goutte-driver": "^1.2", 29 | "behat/mink-selenium2-driver": "1.3.x-dev", 30 | "drupal/coder": "^8.2.12", 31 | "jcalderonzumba/gastonjs": "^1.0.2", 32 | "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", 33 | "mikey179/vfsStream": "^1.2", 34 | "phpunit/phpunit": "^4.8.35 || ^6.1", 35 | "phpspec/prophecy": "^1.4", 36 | "symfony/css-selector": "^3.4.0", 37 | "symfony/phpunit-bridge": "^3.4.3", 38 | "symfony/debug": "^3.4.0", 39 | "mglaman/phpstan-drupal": "^0.11.2", 40 | "phpstan/phpstan-deprecation-rules": "^0.11.0" 41 | 42 | }, 43 | "conflict": { 44 | "drupal/core": "7.*" 45 | }, 46 | "extra": { 47 | "installer-types": [ 48 | "bower-asset", 49 | "npm-asset" 50 | ], 51 | "installer-paths": { 52 | "docroot/core": ["type:drupal-core"], 53 | "docroot/modules/contrib/{$name}/": ["type:drupal-module"], 54 | "docroot/modules/custom/{$name}/": ["type:drupal-module-custom"], 55 | "docroot/themes/contrib/{$name}/": ["type:drupal-theme"], 56 | "docroot/profiles/contrib/{$name}/": ["type:drupal-profile"], 57 | "drush/contrib/{$name}": ["type:drupal-drush"], 58 | "docroot/libraries/{$name}": [ 59 | "type:bower-asset", 60 | "type:npm-asset" 61 | ] 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/orchestration/files/composer-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anavarre/drucker", 3 | "description": "drucker build.", 4 | "type": "project", 5 | "license": "GPL-2.0-or-later", 6 | "minimum-stability": "dev", 7 | "prefer-stable": true, 8 | "repositories": [ 9 | { 10 | "type": "composer", 11 | "url": "https://packages.drupal.org/8" 12 | }, 13 | { 14 | "type": "composer", 15 | "url": "https://asset-packagist.org" 16 | } 17 | ], 18 | "require": { 19 | "composer/installers": "^1.6", 20 | "drupal-composer/drupal-scaffold": "^2.6", 21 | "cweagans/composer-patches": "^1.6", 22 | "drupal/core": "^8.8", 23 | "drush/drush": "^9.6", 24 | "drupal/console": "^1.8", 25 | "zaporylie/composer-drupal-optimizations" : "^1.1.0" 26 | }, 27 | "conflict": { 28 | "drupal/core": "7.*" 29 | }, 30 | "extra": { 31 | "installer-types": [ 32 | "bower-asset", 33 | "npm-asset" 34 | ], 35 | "installer-paths": { 36 | "docroot/core": ["type:drupal-core"], 37 | "docroot/modules/contrib/{$name}/": ["type:drupal-module"], 38 | "docroot/modules/custom/{$name}/": ["type:drupal-module-custom"], 39 | "docroot/themes/contrib/{$name}/": ["type:drupal-theme"], 40 | "docroot/profiles/contrib/{$name}/": ["type:drupal-profile"], 41 | "drush/contrib/{$name}": ["type:drupal-drush"], 42 | "docroot/libraries/{$name}": [ 43 | "type:bower-asset", 44 | "type:npm-asset" 45 | ] 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/orchestration/files/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drucker/home", 3 | "description": "Base dependencies", 4 | "license": "GPL-2.0-or-later", 5 | "require": { 6 | "hirak/prestissimo": "^0.3.9", 7 | "symfony/yaml": "^3.4", 8 | "drush/drush": "^9.6" 9 | }, 10 | "minimum-stability": "dev", 11 | "prefer-stable": true 12 | } 13 | -------------------------------------------------------------------------------- /app/orchestration/files/db-backup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CREDS="root" 4 | HOST="localhost" 5 | MYSQL="$(which mysql)" 6 | MYSQLDUMP="$(which mysqldump)" 7 | BACKUP_DIR="/var/lib/mysql/backup" 8 | QUERY="SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME NOT REGEXP 'backup|mysql|information_schema|performance_schema'" 9 | GZIP="$(which gzip)" 10 | NOW=$(date +"%Y-%m-%d_%R") 11 | 12 | DBS="$(${MYSQL} -h ${HOST} -u ${CREDS} -p${CREDS} -Bse "${QUERY}")" 13 | for DB in ${DBS} 14 | do 15 | FILE=${BACKUP_DIR}/${DB}_${NOW}.gz 16 | ${MYSQLDUMP} -h ${HOST} -u ${CREDS} -p${CREDS} ${DB} | ${GZIP} -9 > ${FILE} 17 | done 18 | -------------------------------------------------------------------------------- /app/orchestration/files/default.vcl: -------------------------------------------------------------------------------- 1 | # 2 | # This is an example VCL file for Varnish. 3 | # 4 | # It does not do anything by default, delegating control to the 5 | # builtin VCL. The builtin VCL is called when there is no explicit 6 | # return statement. 7 | # 8 | # See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/ 9 | # and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples. 10 | 11 | # Marker to tell the VCL compiler that this VCL has been adapted to the 12 | # new 4.0 format. 13 | vcl 4.0; 14 | 15 | # Default backend definition. Set this to point to your content server. 16 | backend default { 17 | .host = "127.0.0.1"; 18 | .port = "8080"; 19 | .connect_timeout = 300s; 20 | .first_byte_timeout = 300s; 21 | .between_bytes_timeout = 300s; 22 | } 23 | 24 | sub vcl_recv { 25 | # Happens before we check if we have this in cache already. 26 | # 27 | # Typically you clean up the request here, removing cookies you don't need, 28 | # rewriting the request, etc. 29 | } 30 | 31 | sub vcl_backend_response { 32 | # Happens after we have read the response headers from the backend. 33 | # 34 | # Here you clean the response headers, removing silly Set-Cookie headers 35 | # and other mistakes your backend does. 36 | } 37 | 38 | sub vcl_deliver { 39 | # Happens when we have all the pieces we need, and are about to send the 40 | # response to the client. 41 | # 42 | # You can do accounting or modifying the final object here. 43 | 44 | # Indicate if the response is a HIT or MISS 45 | if (obj.hits > 0) { 46 | set resp.http.X-Cache = "HIT"; 47 | } else { 48 | set resp.http.X-Cache = "MISS"; 49 | } 50 | 51 | # Indicate how many HITS Varnish has recorded within the allowed TTL 52 | set resp.http.X-Cache-Hits = obj.hits; 53 | } 54 | -------------------------------------------------------------------------------- /app/orchestration/files/drush.site.yml: -------------------------------------------------------------------------------- 1 | local: 2 | root: /var/www/html/SITENAME 3 | uri: http://SITENAME.local 4 | -------------------------------------------------------------------------------- /app/orchestration/files/drush.yml: -------------------------------------------------------------------------------- 1 | drush: 2 | paths: 3 | alias-path: 4 | - /etc/drush 5 | -------------------------------------------------------------------------------- /app/orchestration/files/nginx-template.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen localhost:8080; 3 | server_name drucker.local; 4 | ssl_certificate /etc/nginx/ssl/nginx.crt; 5 | ssl_certificate_key /etc/nginx/ssl/nginx.key; 6 | 7 | listen 443 ssl; 8 | 9 | #root /usr/local/www/mydomain.com; 10 | 11 | #access_log logs/drucker_access.log; 12 | #error_log logs/drucker_error.log; 13 | 14 | location / { 15 | # try_files attempts to serve a file or folder, until it reaches the fallback at the end 16 | try_files $uri @backend; 17 | } 18 | 19 | location @backend { 20 | # essentially the same as passing php requests back to apache 21 | 22 | proxy_set_header X-Real-IP $remote_addr; 23 | proxy_set_header X-Forwarded-For $remote_addr; 24 | proxy_set_header Host $host; 25 | proxy_pass http://0.0.0.0:80; 26 | proxy_connect_timeout 600; 27 | proxy_send_timeout 600; 28 | proxy_read_timeout 600; 29 | send_timeout 600; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/orchestration/files/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | customRulesetUsed: true 3 | reportUnmatchedIgnoredErrors: false 4 | # Ignore phpstan-drupal extension's rules. 5 | ignoreErrors: 6 | - '#\Drupal calls should be avoided in classes, use dependency injection instead#' 7 | - '#Plugin definitions cannot be altered.#' 8 | - '#Missing cache backend declaration for performance.#' 9 | - '#Plugin manager has cache backend specified but does not declare cache tags.#' 10 | includes: 11 | - vendor/mglaman/phpstan-drupal/extension.neon 12 | - vendor/phpstan/phpstan-deprecation-rules/rules.neon -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/elevate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | 20 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/mapping-ISOLatin1Accent.txt: -------------------------------------------------------------------------------- 1 | # This file contains character mappings for the default fulltext field type. 2 | # The source characters (on the left) will be replaced by the respective target 3 | # characters before any other processing takes place. 4 | # Lines starting with a pound character # are ignored. 5 | # 6 | # For sensible defaults, use the mapping-ISOLatin1Accent.txt file distributed 7 | # with the example application of your Solr version. 8 | # 9 | # Examples: 10 | # "À" => "A" 11 | # "\u00c4" => "A" 12 | # "\u00c4" => "\u0041" 13 | # "æ" => "ae" 14 | # "\n" => " " 15 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/protwords.txt: -------------------------------------------------------------------------------- 1 | #----------------------------------------------------------------------- 2 | # This file blocks words from being operated on by the stemmer and word delimiter. 3 | & 4 | < 5 | > 6 | ' 7 | " 8 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/schema_extra_fields.xml: -------------------------------------------------------------------------------- 1 | 7 | 22 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/schema_extra_types.xml: -------------------------------------------------------------------------------- 1 | 10 | 33 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/solrconfig_extra.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | default 4 | AnalyzingInfixLookupFactory 5 | DocumentDictionaryFactory 6 | spell 7 | text 8 | sm_context_tags 9 | false 10 | false 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/solrconfig_spellcheck.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | textSpell 12 | 13 | 14 | 17 | 18 | 19 | 20 | default 21 | spell 22 | solr.DirectSolrSpellChecker 23 | 24 | internal 25 | 26 | 0.5 27 | 28 | 2 29 | 30 | 1 31 | 32 | 5 33 | 34 | 4 35 | 36 | 0.01 37 | 40 | 41 | 42 | 43 | 44 | wordbreak 45 | solr.WordBreakSolrSpellChecker 46 | name 47 | true 48 | true 49 | 10 50 | 51 | 52 | 53 | 63 | 64 | 71 | 78 | 79 | 80 | 89 | 90 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/solrcore.properties: -------------------------------------------------------------------------------- 1 | # Defines Solr properties for this specific core. 2 | solr.replication.master=false 3 | solr.replication.slave=false 4 | solr.replication.pollInterval=00:00:60 5 | solr.replication.masterUrl=http://localhost:8983/solr 6 | solr.replication.confFiles=schema.xml,mapping-ISOLatin1Accent.txt,protwords.txt,stopwords.txt,synonyms.txt,elevate.xml 7 | solr.mlt.timeAllowed=2000 8 | # You should not set your luceneMatchVersion to anything lower than your Solr 9 | # Version. 10 | solr.luceneMatchVersion=6.0 11 | solr.selectSearchHandler.timeAllowed=-1 12 | # autoCommit after 10000 docs 13 | solr.autoCommit.MaxDocs=10000 14 | # autoCommit after 2 minutes 15 | solr.autoCommit.MaxTime=120000 16 | # autoSoftCommit after 2000 docs 17 | solr.autoSoftCommit.MaxDocs=2000 18 | # autoSoftCommit after 10 seconds 19 | solr.autoSoftCommit.MaxTime=10000 20 | solr.install.dir=../../.. 21 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/stopwords.txt: -------------------------------------------------------------------------------- 1 | # Contains words which shouldn't be indexed for fulltext fields, e.g., because 2 | # they're too common. For documentation of the format, see 3 | # http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.StopFilterFactory 4 | # (Lines starting with a pound character # are ignored.) 5 | -------------------------------------------------------------------------------- /app/orchestration/files/solr-conf-7.x/synonyms.txt: -------------------------------------------------------------------------------- 1 | # Contains synonyms to use for your index. For the format used, see 2 | # http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.SynonymFilterFactory 3 | # (Lines starting with a pound character # are ignored.) 4 | -------------------------------------------------------------------------------- /app/orchestration/files/sources.list: -------------------------------------------------------------------------------- 1 | deb http://httpredir.debian.org/debian CODENAME main contrib non-free 2 | deb-src http://httpredir.debian.org/debian CODENAME main contrib non-free 3 | 4 | deb http://httpredir.debian.org/debian CODENAME-updates main contrib non-free 5 | deb-src http://httpredir.debian.org/debian CODENAME-updates main contrib non-free 6 | 7 | deb http://httpredir.debian.org/debian CODENAME-backports main 8 | deb-src http://httpredir.debian.org/debian CODENAME-backports main 9 | 10 | deb http://security.debian.org/ CODENAME/updates main contrib non-free 11 | deb-src http://security.debian.org/ CODENAME/updates main contrib non-free 12 | -------------------------------------------------------------------------------- /app/orchestration/files/ssl/nginx.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFpzCCA4+gAwIBAgIJALVo9DXdWjfPMA0GCSqGSIb3DQEBCwUAMGoxCzAJBgNV 3 | BAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMRAwDgYDVQQKDAdkcnVja2VyMRAw 4 | DgYDVQQDDAdkcnVja2VyMSIwIAYJKoZIhvcNAQkBFhNhZG1pbkBkcnVja2VyLmxv 5 | Y2FsMB4XDTE2MTAxMDEyMDIxNFoXDTE4MTAxMDEyMDIxNFowajELMAkGA1UEBhMC 6 | VVMxEzARBgNVBAgMClNvbWUtU3RhdGUxEDAOBgNVBAoMB2RydWNrZXIxEDAOBgNV 7 | BAMMB2RydWNrZXIxIjAgBgkqhkiG9w0BCQEWE2FkbWluQGRydWNrZXIubG9jYWww 8 | ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDSHcq/kSHGEbkcrakcPBdi 9 | 2BX6qMWMPjbvA8vzoZjRSYdXS8OdMyYSp9StP39xk9zOEmPeCpOEF1GR+bq8KvOM 10 | obXncsaEzU5XIQ7x/0lPQYI0ROekzf9k/9w1eTAYNggCRw0LIPivk5moqOv/RZj0 11 | oo5tvHE5JnQd69u3Dhx4oy6fY/yqI43ICVVPJMGWwtRzVTl3dS5VcP5EAgyFh9vp 12 | +s2NxLMJfC6aQ3OchLXFdbqg9T9BUIJVlvpgqaJBTF2nW8n0ujJcs6ywrWa2f9Ij 13 | PvhIyZanJg9m+NHNW1vUNEoY/mZLiTHyhd8t39Wifx1iemzIJJk6CUnaf8sfUaJj 14 | 99xydeMoos++UvSU4tIxEavP8Qf0WZm/WtWa9/LQP12XJ8JhqB1Y/1Tkz1NkFnX5 15 | mZxXtWe4/cimx33d/Kb9WyQIlGtUi+SWYSIprlSSqScaMXRjGSJ6X8fGbvMy0U6m 16 | CYJII2grE6Mzcmq1GesNilJ+WSij23NnEo7h2JYleqEikRojeZZgp0trm4zeXDmI 17 | QAw7N/PQKN+q1Ki+keReP4VuvusiUOi6Qq+20pDH3/1srln0fLmJ4RWvrIVodgWT 18 | PKD7A92PWctphXJZBqqwq3BNT5owlID1ZYnz8Nz9EfxUwM7ral4jcrGevzKqDpYB 19 | Xfr9r1SBstsBLaVCFSNoJQIDAQABo1AwTjAdBgNVHQ4EFgQUEEeUNvDV7IsaKt7d 20 | jfFAwmTrgxIwHwYDVR0jBBgwFoAUEEeUNvDV7IsaKt7djfFAwmTrgxIwDAYDVR0T 21 | BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAU1cWZFllf1JNiF8+qvzWZUYpfds2 22 | 7PdJ5aJOVRuqo2c7TEabjS+gY4hrFcKnPlizilHKsr2vUUQoCyjgkIhEG7+apBjB 23 | Hf5zF/o76+23EM46wJOb+0tDneq6Hw0eWIL/Whm+I80qhTikrh4Pt81ybm+pSdQ8 24 | vnGtYGkgPi5xkCKzWlC2IkKI2juKssc8gzg1ULyRxbUmexYlS4knTf/C6IrGCWhQ 25 | 4oTjKdC3CnKkyJut8rYdnEQuzip2trPLM3m+kx3QWJw3jC02rPvFo+rQUY1mskqw 26 | 2HV2IHrvUmkMGLe0swDMbGYtVAkOvt2QN2E51nZ/eyz39EIkoIQKp5e/dqCMzk1s 27 | ir1X03najh0aeqlVHR7qyN17H5xE1VFn/BQAv4Kw2IbZljZgyIdQQ7yLHhdcoB/S 28 | S4Pewlw6FojuM8PNckqPyQdZh1GKe9W0+XRdWvEynBB70DRO5p0CKxmvNRMiaJe4 29 | PdyErI5hHIoKdDKTS+mIV14DE/3jL1mgdNUbX/2z9nbICmHJgSQNbDsbU8UZliGW 30 | 5BawLNF/ET1b3Z/cUEk9Q7s0rlFOn0AQfAQX3ABkRnRaDBEEw3DHs7QTmCstDhsB 31 | 51KN3tx+yHH0y6KJh8kP+qFvdYWpY3XwD0SphcqaFAw+6iuGXY6nkpYeGedVhsL6 32 | 0h6XrcbPNSNNutk= 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /app/orchestration/files/ssl/nginx.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDSHcq/kSHGEbkc 3 | rakcPBdi2BX6qMWMPjbvA8vzoZjRSYdXS8OdMyYSp9StP39xk9zOEmPeCpOEF1GR 4 | +bq8KvOMobXncsaEzU5XIQ7x/0lPQYI0ROekzf9k/9w1eTAYNggCRw0LIPivk5mo 5 | qOv/RZj0oo5tvHE5JnQd69u3Dhx4oy6fY/yqI43ICVVPJMGWwtRzVTl3dS5VcP5E 6 | AgyFh9vp+s2NxLMJfC6aQ3OchLXFdbqg9T9BUIJVlvpgqaJBTF2nW8n0ujJcs6yw 7 | rWa2f9IjPvhIyZanJg9m+NHNW1vUNEoY/mZLiTHyhd8t39Wifx1iemzIJJk6CUna 8 | f8sfUaJj99xydeMoos++UvSU4tIxEavP8Qf0WZm/WtWa9/LQP12XJ8JhqB1Y/1Tk 9 | z1NkFnX5mZxXtWe4/cimx33d/Kb9WyQIlGtUi+SWYSIprlSSqScaMXRjGSJ6X8fG 10 | bvMy0U6mCYJII2grE6Mzcmq1GesNilJ+WSij23NnEo7h2JYleqEikRojeZZgp0tr 11 | m4zeXDmIQAw7N/PQKN+q1Ki+keReP4VuvusiUOi6Qq+20pDH3/1srln0fLmJ4RWv 12 | rIVodgWTPKD7A92PWctphXJZBqqwq3BNT5owlID1ZYnz8Nz9EfxUwM7ral4jcrGe 13 | vzKqDpYBXfr9r1SBstsBLaVCFSNoJQIDAQABAoICAB0n8Shf9TXM48js+Bho5j3b 14 | CkG8BZ2OTIUiG7z04YW5FESyyLQZkuDn1QUtWHvkLrGRr7Xx9cJQkgsVgin2M9GB 15 | 5wH01UM8UfCZL7+40u1ig7TJEvO1egkD0ATDij7x0G6weUjgDGIgsyPKPOUxPSZF 16 | IEpt6bAqe9ZjEhv2o1DCJAgOEdNyF4x4bxQKX6qR4nUWkGDZK9LDWSUKu74Tuhpf 17 | qQJRFx7r0nOphHNlnuuFiJ4pKdvgVhWWW6vqHg+9jwlYHVAOPkrKy93AUg5k8j3d 18 | 0QoYnwUWrPB2+nXqhXWOw/Fv67XzlbC3jt6IvtZLmUI/BrVHDtQU0eC19vOjmkrQ 19 | i6Mf2jeDsXGbcIDV0ci7daeJVurigtB/3Hhldg1tpslYBwhq9JomSuVTTCx7I4e3 20 | fAwBBE6if6dNcI6akMcieDpgre7VjxyxD9Wy557bKB7b/QIvgWe5attmxy2CdQMW 21 | oCW3S7F1bLyLhi0adULRnTTWrxTnkDKU+7pbgSzulBDxZMYAeUY9fi4hHeps19bN 22 | TDfOxjhlKYa9BYZh1eRWXIuup0G/yOCBnW6SP+AINFtScsi73SL54wxVm0BOJo6t 23 | JxUhuFiXi2C7M+Kx9k++w5YQAFEfNXfNsXzDyVN1JZ+sqATdtcLoT0UbKF2YgnTy 24 | zwRAMuyRsOBAj8N74L1JAoIBAQDsPAD9dSXX5Ah1NaqMsSs4IO+JR7s/kJ8ZV2Oa 25 | nl7RSrg3SDs7S7GaooZ2V6Vuxthd4bfAlNHX0H3svLsYbSJt/nUq968I2JmWq7w/ 26 | H6iiAatPORAwn2rikXUTSfiVyD+u4qdPClcCre0ZjKaIJ7ST34Yi1zctp+20zC7Y 27 | rFbPaMT5l9JBfpLVKFyHmZfSxDqxIj/lAA6UfdZd9IZRKMuGkp53Dsq0avHdtt7A 28 | IQpdTnCEejSg8vTIK1/3CDq8gQkCQfPCOvxoz5JM/Ru90kI/cgSLNF1w8zHKHg5u 29 | 8IySycX1fh0ppTAmyVtNfmP6VmkZnM79eiT+wnBavQY0WUNLAoIBAQDjslswjVT+ 30 | k/UCyeLlSN5Ko9ibl1eiArxNg50okDWllI9dA7yi1s1tc0QbH3Ia7oAgxH3rscBk 31 | ATrIoSf7uIphieFOh/wd7pdjXGUjKdRi8geuYeKS1WTf1b0gz3KZlsvRfwU6y15d 32 | sNBVTNbet1HJsG/3meUzbApAXN6ZHv/Tj06+XVg4u5AmWegUyyVauJesqx5thn/k 33 | 1pnIY50bD0mjBcknLgYAhTTQ5ww3MDmYZ5vdzv6sCUZ49r9kM8PIhpmMzW0jaou8 34 | 6APZzIIzeqRwvcvnSymvyFhD1lk56Yh3vD8e3++XLtO1sQx7g/JHXjza6tkyISq/ 35 | UMFtZXIbHGxPAoIBACHFfjq9uZhAgDkJYAVW+p++jZ/pgkpXCXec959ODq4K6YT1 36 | rYoPiydZHrHiW8MXaC0brKI6ZDlfE/F5FaIrT+W7n9JxsDMqi+JvUK0RgJEQfgYI 37 | WVkqISScuMj2JTR8eSYuPs7c4o1+gcvKQLBsRLNzHAD1FW1QeXoESpotIQfrqWUp 38 | ICS+zIzuhTPZcEvwQ5e5FrtNI8h0qOWrpFwL4fSuFztcAPyD4WnZz8RVtN6b7Rfz 39 | RHzR3s6S7Ngq9AKoy7nn5coZlqYBLqAU+xdK7K+XRDEGXmlcSvzjCRsxBlehwswS 40 | qGagt96DoKrWa8KJAeNoeGriQFGvSFKgfTeUnzsCggEADv3gSSsVDIn7WMqoGMaa 41 | dDmjemMVjwI1GblvsIsGLTfB1LL5SZNxBSLQuiRw49sOLpohXFJgw3TdRPZvZoB5 42 | BAELB5umeuYJq64arp0DcdxTqySgwWAxexdck3t1JS2rj8iYNI3NUcfhf6xGfXV+ 43 | ehQW2yuTzrXvWtuCgHxtBaXq3lfRBjM7Q3sp76yMchOzUNgXccioRQ3oJCyC3JQ+ 44 | GfC4lM7P8FrU5mhAAqY3NJSly43kcLlPnYlJgrRx0JMkKwQfinRqbO6tyjpP3EnX 45 | 5+BnO3xUa1F6lkTXrRt2M8P+N+8wnDimEdFta/h9DDvlL9jEoitS4DPV+Hj0cVqG 46 | uwKCAQBfI4vLMoIyPROY4JJpa1P7bBlAtOKV58SoMkG0FHtUmIXyYLwwavMdN0q2 47 | sOy8I6eKzapWv/EtEfVyJiSzlAj759CQazLg3+8KHaECsWQmBTCTyYEO2hNFoPbJ 48 | 4MtIe0fJrkqjep2ciDBNiBkILfTSpPqLruQqc47nPDejAScb/rklHDbdDmHEIFQ+ 49 | DMga2jAWPGCc5eQR/f06q+ZnYdjii81hxM+GfkJ6Ay4j8ZIQDFmP3cvaEjvfV5v2 50 | v0Rds3tynkuoa3LwTV4kb5uSdI6F71aeGHTqwN6rrurYRjxvleGWZbNKXfujFv0i 51 | pd3xWyS6zeBjbcBMunmqR07fBNhI 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /app/orchestration/files/varnish: -------------------------------------------------------------------------------- 1 | # Configuration file for varnish 2 | # 3 | # /etc/init.d/varnish expects the variables $DAEMON_OPTS, $NFILES and $MEMLOCK 4 | # to be set from this shell script fragment. 5 | # 6 | # Note: If systemd is installed, this file is obsolete and ignored. Please see 7 | # /usr/share/doc/varnish/examples/varnish.systemd-drop-in.conf 8 | 9 | # Should we start varnishd at boot? Set to "no" to disable. 10 | START=yes 11 | 12 | # Maximum number of open files (for ulimit -n) 13 | NFILES=131072 14 | 15 | # Maximum locked memory size (for ulimit -l) 16 | # Used for locking the shared memory log in memory. If you increase log size, 17 | # you need to increase this number as well 18 | MEMLOCK=82000 19 | 20 | # Default varnish instance name is the local nodename. Can be overridden with 21 | # the -n switch, to have more instances on a single server. 22 | # You may need to uncomment this variable for alternatives 1 and 3 below. 23 | # INSTANCE=$(uname -n) 24 | 25 | # This file contains 4 alternatives, please use only one. 26 | 27 | ## Alternative 1, Minimal configuration, no VCL 28 | # 29 | # Listen on port 6081, administration on localhost:6082, and forward to 30 | # content server on localhost:8080. Use a 1GB fixed-size cache file. 31 | # 32 | # This example uses the INSTANCE variable above, which you need to uncomment. 33 | # 34 | # DAEMON_OPTS="-a :6081 \ 35 | # -T localhost:6082 \ 36 | # -b localhost:8080 \ 37 | # -u varnish -g varnish \ 38 | # -S /etc/varnish/secret \ 39 | # -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G" 40 | 41 | 42 | ## Alternative 2, Configuration with VCL 43 | # 44 | # Listen on port 6081, administration on localhost:6082, and forward to 45 | # one content server selected by the vcl file, based on the request. 46 | # 47 | DAEMON_OPTS="-a 0.0.0.0:80 48 | -T localhost:6082 \ 49 | -f /etc/varnish/default.vcl \ 50 | -S /etc/varnish/secret \ 51 | -s malloc,256m \ 52 | -p http_resp_hdr_len=10000" 53 | 54 | ## Alternative 3, Advanced configuration 55 | # 56 | # This example uses the INSTANCE variable above, which you need to uncomment. 57 | # 58 | # See varnishd(1) for more information. 59 | # 60 | # # Main configuration file. You probably want to change it :) 61 | # VARNISH_VCL_CONF=/etc/varnish/default.vcl 62 | # 63 | # # Default address and port to bind to 64 | # # Blank address means all IPv4 and IPv6 interfaces, otherwise specify 65 | # # a host name, an IPv4 dotted quad, or an IPv6 address in brackets. 66 | # VARNISH_LISTEN_ADDRESS= 67 | # VARNISH_LISTEN_PORT=6081 68 | # 69 | # # Telnet admin interface listen address and port 70 | # VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 71 | # VARNISH_ADMIN_LISTEN_PORT=6082 72 | # 73 | # # Cache file location 74 | # VARNISH_STORAGE_FILE=/var/lib/varnish/$INSTANCE/varnish_storage.bin 75 | # 76 | # # Cache file size: in bytes, optionally using k / M / G / T suffix, 77 | # # or in percentage of available disk space using the % suffix. 78 | # VARNISH_STORAGE_SIZE=1G 79 | # 80 | # # File containing administration secret 81 | # VARNISH_SECRET_FILE=/etc/varnish/secret 82 | # 83 | # # Backend storage specification 84 | # VARNISH_STORAGE="file,${VARNISH_STORAGE_FILE},${VARNISH_STORAGE_SIZE}" 85 | # 86 | # # Default TTL used when the backend does not specify one 87 | # VARNISH_TTL=120 88 | # 89 | # # DAEMON_OPTS is used by the init script. If you add or remove options, make 90 | # # sure you update this section, too. 91 | # DAEMON_OPTS="-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \ 92 | # -f ${VARNISH_VCL_CONF} \ 93 | # -T ${VARNISH_ADMIN_LISTEN_ADDRESS}:${VARNISH_ADMIN_LISTEN_PORT} \ 94 | # -t ${VARNISH_TTL} \ 95 | # -S ${VARNISH_SECRET_FILE} \ 96 | # -s ${VARNISH_STORAGE}" 97 | # 98 | 99 | 100 | ## Alternative 4, Do It Yourself 101 | # 102 | # DAEMON_OPTS="" 103 | -------------------------------------------------------------------------------- /app/orchestration/handlers.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Restart SSH 3 | service: 4 | name: ssh 5 | state: restarted 6 | 7 | - name: Restart Apache 8 | service: 9 | name: apache2 10 | state: restarted 11 | 12 | - name: Start Apache 13 | service: 14 | name: apache2 15 | state: started 16 | 17 | - name: Reload Apache 18 | service: 19 | name: apache2 20 | state: reloaded 21 | 22 | - name: Restart PHP-FPM 23 | service: 24 | name: php{{ default_php_version }}-fpm 25 | state: restarted 26 | 27 | - name: Restart MySQL 28 | service: 29 | name: mysql 30 | state: restarted 31 | 32 | - name: Restart Varnish 33 | service: 34 | name: varnish 35 | state: restarted 36 | 37 | - name: Start nginx 38 | service: 39 | name: nginx 40 | state: started 41 | 42 | - name: Reload nginx 43 | service: 44 | name: nginx 45 | state: reloaded 46 | 47 | - name: Restart Solr 48 | shell: "{{ solr_binary }} restart" 49 | become: yes 50 | become_user: solr 51 | -------------------------------------------------------------------------------- /app/orchestration/hosts: -------------------------------------------------------------------------------- 1 | [drucker_base] 2 | 203.0.113.99 3 | 4 | [drucker_mirror] 5 | 203.0.113.50 6 | 7 | [drucker_edge] 8 | 203.0.113.2 9 | 10 | [drucker_web] 11 | 203.0.113.10 12 | 13 | [drucker_db] 14 | 203.0.113.12 15 | 16 | [drucker_search] 17 | 203.0.113.13 18 | -------------------------------------------------------------------------------- /app/orchestration/plays/app/delete.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "DELETE: Delete database" 3 | mysql_db: 4 | login_user: "{{ db_creds }}" 5 | login_password: "{{ db_creds }}" 6 | login_host: "{{ db_ip }}" 7 | login_port: "{{ db_port }}" 8 | config_file: "{{ db_config }}" 9 | name: "{{ sitename }}" 10 | state: absent 11 | 12 | - name: "DELETE: Check if docroot exists" 13 | stat: 14 | path: "{{ drupal_root }}" 15 | register: docroot_check 16 | ignore_errors: True 17 | 18 | - name: "DELETE: Delete docroot" 19 | file: 20 | path: "{{ drupal_root }}" 21 | state: absent 22 | force: yes 23 | when: docroot_check.stat.exists == true and sitename != 'import' 24 | 25 | - name: "DELETE: Check if vHost exists" 26 | stat: 27 | path: "{{ sites_enabled }}/{{ sitename }}.conf" 28 | register: apache_conf 29 | ignore_errors: True 30 | 31 | - name: "DELETE: Delete vHost" 32 | file: 33 | path: "{{ item }}" 34 | state: absent 35 | with_items: 36 | - "{{ sites_available }}/{{ sitename }}.conf" 37 | - "{{ sites_enabled }}/{{ sitename }}.conf" 38 | when: apache_conf.stat.exists == true 39 | 40 | - name: "DELETE: Delete Apache log files" 41 | file: 42 | path: "{{ log_dir }}/{{ item }}" 43 | state: absent 44 | with_items: 45 | - "{{ sitename }}-access.log" 46 | - "{{ sitename }}-error.log" 47 | when: apache_conf.stat.exists == true 48 | 49 | - name: "DELETE: Delete Apache log files" 50 | file: 51 | path: "{{ log_dir }}/{{ item }}" 52 | state: absent 53 | with_items: 54 | - "{{ sitename }}-access.log" 55 | - "{{ sitename }}-error.log" 56 | when: apache_conf.stat.exists == true 57 | 58 | # Docker provides the container with a custom /etc/hosts file so we have to hack 59 | # our way through modifying it. 60 | - name: "DELETE: Copy hosts file" 61 | command: cp {{ hosts_file }} {{ tmp_hosts_file }} 62 | when: apache_conf.stat.exists == true 63 | 64 | - name: "DELETE: Remove hosts entry" 65 | lineinfile: 66 | dest: "{{ tmp_hosts_file }}" 67 | line: "{{ web_ip }}\t{{ sitename }}.{{ tld }}" 68 | state: absent 69 | when: apache_conf.stat.exists == true 70 | 71 | - name: "DELETE: Replace hosts file" 72 | command: cp {{ tmp_hosts_file }} {{ hosts_file }} 73 | when: apache_conf.stat.exists == true 74 | 75 | - name: "DELETE: Check if Drush alias exist" 76 | stat: 77 | path: "{{ drush_alias_path }}/{{ sitename }}.{{ drush_alias_extension }}" 78 | register: sitename_alias 79 | 80 | - name: "DELETE: Delete Drush alias" 81 | file: 82 | path: "{{ drush_alias_path }}/{{ sitename }}.{{ drush_alias_extension }}" 83 | state: absent 84 | when: sitename_alias.stat.exists == true 85 | 86 | - import_tasks: ../common/app-registry.yml 87 | -------------------------------------------------------------------------------- /app/orchestration/plays/app/drupal.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "DRUPAL: Check if new site exists" 3 | stat: 4 | path: "{{ drupal_root }}" 5 | register: new_site 6 | ignore_errors: True 7 | 8 | - name: "DRUPAL: Check if new database exists" 9 | stat: 10 | path: "{{ db_data }}/{{ sitename }}" 11 | register: new_db 12 | 13 | - name: "DRUPAL: Create new site architecture" 14 | file: 15 | path: "{{ drupal_root }}" 16 | state: directory 17 | become: yes 18 | become_user: "{{ user }}" 19 | when: new_site.stat.exists == false 20 | 21 | - name: "DRUPAL: Deploy default composer.json template" 22 | copy: 23 | src: "{{ composer_json_template_file }}" 24 | dest: "{{ drupal_composer_json }}" 25 | mode: 0644 26 | become: yes 27 | become_user: "{{ user }}" 28 | when: new_site.stat.exists == false 29 | 30 | - name: "DRUPAL: Pin Drupal version to specific Git tag" 31 | replace: 32 | dest: "{{ drupal_composer_json }}" 33 | regexp: '^(.*)"drupal/core": "\^8.7"(.*)$' 34 | replace: '\1"drupal/core": "{{ git_tag }}"\2' 35 | when: new_site.stat.exists == false and git_tag is defined 36 | 37 | - name: "DRUPAL: Install vendor dependencies from composer.json file (this can take a while)" 38 | composer: 39 | command: install 40 | working_dir: "{{ drupal_root }}" 41 | become: yes 42 | become_user: "{{ user }}" 43 | 44 | - import_tasks: ../common/drupal-common.yml 45 | 46 | - name: "DRUPAL: Install Drupal" 47 | command: drush --root={{ drupal_root }} site-install standard install_configure_form.enable_update_status_module=NULL -qy --db-url=mysql://{{ db_creds }}:{{ db_creds }}@{{ db_ip }}:{{ db_port }}/{{ sitename }} --site-name={{ sitename }} --site-mail={{ drupal_creds }}@{{ sitename }}.{{ tld }} --account-name={{ drupal_creds }} --account-pass={{ drupal_creds }} --account-mail={{ drupal_creds }}@{{ sitename }}.{{ tld }} 48 | become: yes 49 | become_user: "{{ user }}" 50 | when: new_alias.stat.exists == false 51 | 52 | - name: "DRUPAL: Check if .gitignore exists" 53 | stat: 54 | path: "{{ drupal_root }}/.gitignore" 55 | register: gitignore_check 56 | ignore_errors: True 57 | 58 | - name: "DRUPAL: Create .gitignore file" 59 | copy: 60 | src: "{{ gitignore_source_file }}" 61 | dest: "{{ drupal_root }}" 62 | mode: 0644 63 | become: yes 64 | become_user: "{{ user }}" 65 | when: gitignore_check.stat.exists == false 66 | 67 | - name: "DRUPAL: Initialize Git repository" 68 | shell: git -C {{ drupal_root }} init 69 | args: 70 | warn: no 71 | register: initial_commit 72 | become: yes 73 | become_user: "{{ user }}" 74 | when: gitignore_check.stat.exists == false 75 | 76 | - name: "DRUPAL: Add all new files under version control" 77 | shell: git -C {{ drupal_root }} add --all . && git -C {{ drupal_root }} commit -m "Initial commit" 78 | become: yes 79 | become_user: "{{ user }}" 80 | when: gitignore_check.stat.exists == false 81 | 82 | - name: "DRUPAL: Make sure files dir ownership is correct" 83 | file: 84 | path: "{{ drupal_docroot }}/{{ default_site }}/files" 85 | owner: "{{ user }}" 86 | group: "{{ apache_user }}" 87 | recurse: yes 88 | when: new_site.stat.exists == false or new_db.stat.exists == false 89 | 90 | - name: "DRUPAL: Make sure files dir ownership is correct" 91 | file: 92 | path: "{{ drupal_docroot }}/{{ default_site }}/files" 93 | owner: "{{ user }}" 94 | group: "{{ apache_user }}" 95 | recurse: yes 96 | when: new_site.stat.exists == false or new_db.stat.exists == false 97 | 98 | - import_tasks: ../common/app-registry.yml 99 | -------------------------------------------------------------------------------- /app/orchestration/plays/app/lightning.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "LIGHTNING: Check if new site exists" 3 | stat: 4 | path: "{{ drupal_root }}" 5 | register: new_site 6 | ignore_errors: True 7 | 8 | - name: "LIGHTNING: Check if new database exists" 9 | stat: 10 | path: "{{ db_data }}/{{ sitename }}" 11 | register: new_db 12 | 13 | # We're using the shell command here, because using the composer command leaves us 14 | # with missing vendor dependencies, for some reason. 15 | - name: "LIGHTNING: Create project with vendor dependencies (this can take a while)" 16 | shell: cd {{ webroot }} && composer create-project acquia/lightning-project {{ sitename }} ^8.6 --no-interaction 17 | become: yes 18 | become_user: "{{ user }}" 19 | 20 | - import_tasks: ../common/drupal-common.yml 21 | 22 | - name: "LIGHTNING: Install Drupal" 23 | command: drush --root={{ drupal_docroot }} site-install lightning install_configure_form.enable_update_status_module=NULL -qy --db-url=mysql://{{ db_creds }}:{{ db_creds }}@{{ db_ip }}:{{ db_port }}/{{ sitename }} --site-name={{ sitename }} --site-mail={{ drupal_creds }}@{{ sitename }}.{{ tld }} --account-name={{ drupal_creds }} --account-pass={{ drupal_creds }} --account-mail={{ drupal_creds }}@{{ sitename }}.{{ tld }} 24 | become: yes 25 | become_user: "{{ user }}" 26 | when: new_alias.stat.exists == false 27 | 28 | - name: "LIGHTNING: Check if phpunit.xml file exists" 29 | stat: 30 | path: "{{ drupal_docroot }}/core/phpunit.xml" 31 | register: lightning_phpunit 32 | 33 | - name: "LIGHTNING: Deploy phpunit.xml file" 34 | copy: 35 | src: "{{ phpunit_source_file }}" 36 | dest: "{{ drupal_docroot }}/core/" 37 | mode: 0644 38 | become: yes 39 | become_user: "{{ user }}" 40 | when: lightning_phpunit.stat.exists == false 41 | 42 | - name: "LIGHTNING: Modify phpunit.xml file" 43 | replace: 44 | dest: "{{ drupal_docroot }}/core/phpunit.xml" 45 | regexp: '^(.*)SITENAME(.*)$' 46 | replace: '\1{{ sitename }}\2' 47 | when: lightning_phpunit.stat.exists == false 48 | 49 | - name: "LIGHTNING: Make sure we're down one level for the PHPUnit path" 50 | replace: 51 | dest: "{{ drupal_docroot }}/core/phpunit.xml" 52 | regexp: '^(.*){{ drupal_root }}(.*)$' 53 | replace: '\1{{ drupal_root }}/docroot\2' 54 | when: lightning_phpunit.stat.exists == false 55 | 56 | - name: "LIGHTNING: Check if .gitignore exists" 57 | stat: 58 | path: "{{ drupal_root }}/.gitignore" 59 | register: lightning_gitignore 60 | ignore_errors: True 61 | 62 | - name: "LIGHTNING: Create .gitignore file" 63 | copy: 64 | src: "{{ gitignore_source_file }}" 65 | dest: "{{ drupal_root }}" 66 | mode: 0644 67 | become: yes 68 | become_user: "{{ user }}" 69 | when: lightning_gitignore.stat.exists == false 70 | 71 | - name: "LIGHTNING: Check if Git repository exists" 72 | stat: 73 | path: "{{ drupal_root }}/.git" 74 | register: lightning_git_repo 75 | ignore_errors: True 76 | 77 | - name: "LIGHTNING: Initialize Git repository" 78 | shell: git -C {{ drupal_root }} init 79 | args: 80 | warn: no 81 | register: initial_commit 82 | become: yes 83 | become_user: "{{ user }}" 84 | when: lightning_git_repo.stat.exists == false 85 | 86 | - name: "LIGHTNING: Add all new files under version control" 87 | shell: git -C {{ drupal_root }} add --all . && git -C {{ drupal_root }} commit -m "Initial commit" 88 | become: yes 89 | become_user: "{{ user }}" 90 | when: lightning_git_repo.stat.exists == false 91 | 92 | - name: "LIGHTNING: Make sure files dir ownership is correct" 93 | file: 94 | path: "{{ drupal_root }}/{{ default_site }}/files" 95 | owner: "{{ user }}" 96 | group: "{{ apache_user }}" 97 | state: directory 98 | recurse: yes 99 | when: new_site.stat.exists == false or new_db.stat.exists == false 100 | 101 | - import_tasks: ../common/app-registry.yml 102 | -------------------------------------------------------------------------------- /app/orchestration/plays/app/prod.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PROD: Disable settings.local.php" 3 | blockinfile: 4 | dest: "{{ deployed_settings_php }}" 5 | block: | 6 | if (file_exists(__DIR__ . '/settings.local.php')) { 7 | include __DIR__ . '/settings.local.php'; 8 | } 9 | 10 | state: absent 11 | marker: "# {mark} MANAGED SETTINGS.LOCAL.PHP BLOCK" 12 | 13 | - name: "PROD: Check if services.yml exists" 14 | stat: 15 | path: "{{ deployed_services_yml }}" 16 | register: deployed_services_yml_prod 17 | ignore_errors: True 18 | 19 | - name: "PROD: Turn off Twig debugging" 20 | replace: 21 | dest: "{{ deployed_services_yml }}" 22 | regexp: '^(.*) debug: true(.*)$' 23 | replace: '\1 debug: false\2' 24 | register: turn_off_twig_debugging 25 | when: deployed_services_yml_prod.stat.exists == true 26 | 27 | - name: "PROD: Turn off Twig auto_reload" 28 | replace: 29 | dest: "{{ deployed_services_yml }}" 30 | regexp: '^(.*) auto_reload: true(.*)$' 31 | replace: '\1 auto_reload: null\2' 32 | when: deployed_services_yml_prod.stat.exists == true 33 | 34 | - name: "PROD: Turn on Twig caching" 35 | replace: 36 | dest: "{{ deployed_services_yml }}" 37 | regexp: '^(.*) cache: false(.*)$' 38 | replace: '\1 cache: true\2' 39 | when: deployed_services_yml_prod.stat.exists == true 40 | 41 | - name: "PROD: Check if the Testing module is installed" 42 | shell: drush --root={{ drupal_root }} pm-list --type=module --status=enabled | grep simpletest | awk '{print $4}' 43 | register: testing_module_check 44 | 45 | - name: "PROD: Uninstall the Testing module" 46 | command: drush --root={{ drupal_root }} pm-uninstall -y simpletest 47 | when: testing_module_check.stdout == "Enabled" 48 | 49 | - name: "PROD: Delete composer.lock file" 50 | file: 51 | path: "{{ drupal_composer_lock }}" 52 | state: absent 53 | force: yes 54 | 55 | - name: "PROD: Deploy composer.json template" 56 | copy: 57 | src: "{{ composer_json_template_file }}" 58 | dest: "{{ drupal_composer_json }}" 59 | mode: 0644 60 | become: yes 61 | become_user: "{{ user }}" 62 | 63 | # We're using the shell command here, because using the composer command leaves us 64 | # with missing vendor dependencies, for some reason. 65 | - name: "PROD: Remove require-dev vendor dependencies (this can take a while)" 66 | shell: composer install 67 | args: 68 | chdir: "{{ drupal_root }}" 69 | become: yes 70 | become_user: "{{ user }}" 71 | 72 | - name: "PROD: Check if phpstan.neon exists" 73 | stat: 74 | path: "{{ phpstan_neon }}" 75 | register: phpstan 76 | ignore_errors: True 77 | 78 | - name: "PROD: Delete phpstan.neon" 79 | file: 80 | path: "{{ phpstan_neon }}" 81 | state: absent 82 | when: phpstan.stat.exists == true 83 | 84 | - name: "PROD: Rebuild Drupal cache" 85 | command: drush --root={{ drupal_root }} cache-rebuild 86 | when: turn_off_twig_debugging.changed 87 | 88 | - name: "PROD: Check the Zend assertions status" 89 | shell: grep "^zend.assertions = 1" "{{ default_php_ini }}" || echo "off" 90 | register: zend_assertions_disable 91 | changed_when: zend_assertions_disable.stdout != "off" 92 | 93 | - name: "PROD: Turn off Zend assertions" 94 | replace: 95 | dest: "{{ default_php_ini }}" 96 | regexp: '^(.*)zend.assertions = 1(.*)$' 97 | replace: '\1zend.assertions = -1\2' 98 | when: zend_assertions_disable.stdout != "off" 99 | 100 | - name: "PROD: Prevent errors from showing up on screen" 101 | replace: 102 | dest: "{{ default_php_ini }}" 103 | regexp: '^(.*)display_errors = On(.*)$' 104 | replace: '\1display_errors = Off\2' 105 | notify: Restart Apache 106 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/apache-installation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "APACHE: Check if server is installed" 3 | stat: 4 | path: "{{ apache_security_conf }}" 5 | register: apache 6 | ignore_errors: True 7 | 8 | - name: "APACHE: Install server and web tools" 9 | package: 10 | name: "{{ item }}" 11 | state: present 12 | with_items: 13 | - apache2 14 | - apache2-utils 15 | - goaccess 16 | when: apache.stat.exists == false 17 | 18 | - name: "APACHE: Enable required modules" 19 | apache2_module: 20 | name: "{{ item }}" 21 | state: present 22 | with_items: 23 | - actions 24 | - rewrite 25 | - proxy_http 26 | when: apache.stat.exists == false 27 | 28 | - name: "APACHE: Ensure APACHE_RUN_USER is set to the expected user" 29 | lineinfile: 30 | dest: "{{ apache_envvars }}" 31 | regexp: "export APACHE_RUN_USER=www-data" 32 | line: "export APACHE_RUN_USER={{ user }}" 33 | when: apache.stat.exists == false 34 | 35 | - name: "APACHE: Fix the POODLE SSL v3 vulnerability" 36 | lineinfile: 37 | dest: "{{ apache_ssl_mod }}" 38 | regexp: "SSLProtocol all" 39 | line: "\tSSLProtocol all -SSLv2 -SSLv3" 40 | when: apache.stat.exists == false 41 | 42 | - name: "APACHE: Delete default vHost" 43 | file: 44 | path: "{{ default_vhost }}" 45 | state: absent 46 | when: apache.stat.exists == false 47 | 48 | - name: "APACHE: Delete default vHost symlink" 49 | file: 50 | path: "{{ default_vhost }}" 51 | state: absent 52 | when: apache.stat.exists == false 53 | 54 | - name: "APACHE: Ensure Apache is started" 55 | service: 56 | name: apache2 57 | enabled: yes 58 | state: started 59 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/apache-vhost-fcgi.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Store PHP version variable" 3 | shell: cat {{ default_php_version_file }} 4 | register: phpfcgi_read_version 5 | 6 | - name: "PHP: Add support for php-fpm Fast-CGI" 7 | blockinfile: 8 | dest: "{{ sites_available }}/{{ sitename }}.conf" 9 | block: |6 10 | ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/var/run/php/php{{ phpfcgi_read_version.stdout }}-fpm.sock|fcgi://127.0.0.1:9000/var/www/html/{{ sitename }}/docroot/ 11 | insertafter: '^(.*)DocumentRoot(.*)$' 12 | marker: "# {mark} MANAGED PHP-FPM FAST-CGI BLOCK" 13 | when: new_vhost_check.stat.exists == false 14 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/apache-vhost.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "APACHE: Check if new vHost exists" 3 | stat: 4 | path: "{{ sites_enabled }}/{{ sitename }}.conf" 5 | register: new_vhost_check 6 | ignore_errors: True 7 | 8 | - name: "APACHE: Deploy default vHost template" 9 | copy: 10 | src: "{{ apache_template_source_file }}" 11 | dest: "{{ sites_available }}" 12 | mode: 0644 13 | when: new_vhost_check.stat.exists == false 14 | 15 | - name: "APACHE: Rename default vHost template" 16 | command: mv {{ vhost_template }} {{ sites_available }}/{{ sitename }}.conf 17 | when: new_vhost_check.stat.exists == false 18 | 19 | - name: "APACHE: Modify new vHost" 20 | replace: 21 | dest: "{{ sites_available }}/{{ sitename }}.conf" 22 | regexp: '^(.*)SITENAME(.*)$' 23 | replace: '\1{{ sitename }}\2' 24 | when: new_vhost_check.stat.exists == false 25 | 26 | - import_tasks: apache-vhost-fcgi.yml 27 | 28 | - name: "APACHE: Enable new vHost" 29 | file: 30 | src: ../sites-available/{{ sitename }}.conf 31 | dest: "{{ sites_enabled }}/{{ sitename }}.conf" 32 | state: link 33 | force: yes 34 | register: test 35 | notify: Reload Apache 36 | when: new_vhost_check.stat.exists == false 37 | 38 | # Docker provides the container with a custom /etc/hosts file so we have to hack 39 | # our way through modifying it. 40 | - name: "SYSTEM: Copy hosts file" 41 | command: cp {{ hosts_file }} {{ tmp_hosts_file }} 42 | when: new_vhost_check.stat.exists == false 43 | 44 | - name: "SYSTEM: Add new entry" 45 | lineinfile: 46 | dest: "{{ tmp_hosts_file }}" 47 | line: "{{ web_ip }}\t{{ sitename }}.{{ tld }}" 48 | when: new_vhost_check.stat.exists == false 49 | 50 | - name: "SYSTEM: Replace hosts file" 51 | command: cp {{ tmp_hosts_file }} {{ hosts_file }} 52 | when: new_vhost_check.stat.exists == false 53 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/app-registry.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "APP REGISTRY: Check if app registry file exists" 3 | stat: 4 | path: "{{ app_registry }}" 5 | register: app_registry_file 6 | ignore_errors: True 7 | 8 | - name: "APP REGISTRY: Create app registry file" 9 | copy: 10 | content: "" 11 | dest: "{{ app_registry }}" 12 | force: no 13 | mode: 02444 14 | owner: "{{ user }}" 15 | group: "{{ apache_user }}" 16 | when: app_registry_file.stat.exists == false 17 | 18 | - name: "APP REGISTRY: Register app" 19 | lineinfile: 20 | dest: "{{ app_registry }}" 21 | line: "{{ sitename}} ({{ app }})" 22 | when: app is defined and app != "delete" 23 | 24 | - name: "APP REGISTRY: Unregister app" 25 | lineinfile: 26 | dest: "{{ app_registry }}" 27 | regexp: '^{{ sitename}}' 28 | line: "{{ sitename}} ({{ app }})" 29 | state: absent 30 | when: app is defined and app == "delete" 31 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/apt-repos.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if deb.sury.org repository exists" 3 | stat: 4 | path: "{{ sury_repo }}" 5 | register: sury_repo_check 6 | changed_when: sury_repo_check.stat.exists == false 7 | 8 | - name: "PHP: Add deb.sury.org GPG signature" 9 | apt_key: 10 | url: "{{ sury_gpg }}" 11 | state: present 12 | validate_certs: no 13 | when: sury_repo_check.stat.exists == false 14 | 15 | - name: "PHP: Add deb.sury.org repository" 16 | apt_repository: 17 | repo: "{{ sury_deb }}" 18 | state: present 19 | changed_when: sury_repo_check.stat.exists == false 20 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/apt-update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "SYSTEM: Check if APT cache needs to be updated" 3 | apt: 4 | update_cache: yes 5 | cache_valid_time: 86400 6 | register: apt_cache_check 7 | changed_when: apt_cache_check.cache_updated == true 8 | ignore_errors: true 9 | 10 | - name: "SYSTEM: Update APT cache and upgrade the container" 11 | apt: 12 | upgrade: safe 13 | update_cache: yes 14 | when: apt_cache_check.cache_updated == true 15 | ignore_errors: true -------------------------------------------------------------------------------- /app/orchestration/plays/common/database.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MYSQL: Ensure database is wiped before installing" 3 | mysql_db: 4 | login_user: "{{ db_creds }}" 5 | login_password: "{{ db_creds }}" 6 | login_host: "{{ db_ip }}" 7 | login_port: "{{ db_port }}" 8 | name: "{{ sitename }}" 9 | config_file: "{{ db_config }}" 10 | state: absent 11 | when: new_site.stat.exists == false 12 | 13 | - name: "MYSQL: Create new database" 14 | mysql_db: 15 | login_user: "{{ db_creds }}" 16 | login_password: "{{ db_creds }}" 17 | login_host: "{{ db_ip }}" 18 | login_port: "{{ db_port }}" 19 | name: "{{ sitename }}" 20 | config_file: "{{ db_config }}" 21 | state: present 22 | when: new_site.stat.exists == false or new_db.stat.exists == false 23 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/drucker-config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "DRUCKER: Check if import directories exist" 3 | stat: 4 | path: "{{ item }}" 5 | with_items: 6 | - "{{ import_dir }}" 7 | - "{{ archives_dir }}" 8 | register: import_directories 9 | ignore_errors: True 10 | 11 | - name: "DRUCKER Create import directories" 12 | file: 13 | path: "{{ item }}" 14 | state: directory 15 | mode: 0755 16 | owner: "{{ user }}" 17 | group: "{{ apache_user }}" 18 | with_items: 19 | - "{{ import_dir }}" 20 | - "{{ archives_dir }}" 21 | when: import_directories.results[0]['item'] or import_directories.results[1]['item'] 22 | 23 | - name: "DRUCKER: Check if README file exists" 24 | stat: 25 | path: "{{ imported_readme }}" 26 | register: readme_import 27 | 28 | - name: "DRUCKER: Deploy README file" 29 | copy: 30 | src: "{{ readme_import_source_file }}" 31 | dest: "{{ imported_readme }}" 32 | mode: 0644 33 | owner: "{{ user }}" 34 | group: "{{ apache_user }}" 35 | when: readme_import.stat.exists == false 36 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/drush-aliases.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "DRUSH: Check if new alias exist" 3 | stat: 4 | path: "{{ drush_alias_path }}/{{ sitename }}.{{ drush_alias_extension }}" 5 | register: new_alias 6 | 7 | - name: "DRUSH: Deploy new alias" 8 | copy: 9 | src: "{{ drush_alias_source_file }}" 10 | dest: "{{ drush_alias_path }}" 11 | mode: 0644 12 | when: new_alias.stat.exists == false 13 | ignore_errors: true 14 | 15 | - name: "DRUSH: Rename default alias" 16 | command: mv {{ drush_alias_filepath }} {{ drush_alias_path }}/{{ sitename }}.{{ drush_alias_extension }} 17 | when: new_alias.stat.exists == false 18 | 19 | - name: "DRUSH: Modify alias" 20 | replace: 21 | dest: "{{ drush_alias_path }}/{{ sitename }}.{{ drush_alias_extension }}" 22 | regexp: '^(.*)SITENAME(.*)$' 23 | replace: '\1{{ sitename }}\2' 24 | when: new_alias.stat.exists == false 25 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/mirror-deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MIRROR: Check if apt.conf exists" 3 | stat: 4 | path: "{{ mirror_apt_conf_file }}" 5 | register: apt_conf_exists 6 | 7 | - name: "MIRROR: Deploy apt.conf file" 8 | copy: 9 | src: "{{ mirror_source_file }}" 10 | dest: /etc/apt 11 | mode: 0644 12 | when: apt_conf_exists.stat.exists == false 13 | 14 | - name: "MIRROR: Update apt.conf file with expected values" 15 | replace: 16 | dest: "{{ mirror_apt_conf_file }}" 17 | regexp: '^(.*)HOST:PORT(.*)$' 18 | replace: '\1{{ mirror_host }}:{{ mirror_port }}\2' 19 | when: apt_conf_exists.stat.exists == false 20 | 21 | - name: "MIRROR: Check if the APT mirror hostname is configured" 22 | shell: grep -o "{{ mirror_ip }}" {{ hosts_file }} || echo "absent" 23 | register: mirror_hostname 24 | changed_when: mirror_hostname.stdout == "absent" 25 | 26 | - name: "MIRROR: Make sure the container can talk to the APT mirror proxy" 27 | shell: echo "{{ mirror_ip }} {{ mirror_host }}" >> {{ hosts_file }} 28 | when: mirror_hostname.stdout == "absent" 29 | -------------------------------------------------------------------------------- /app/orchestration/plays/common/permissions.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PREP: Check if /var/www exists" 3 | stat: 4 | path: "{{ www_dir }}" 5 | register: www_dir_exists 6 | 7 | - name: "PREP: Check /var/www permissions recursively" 8 | command: find "{{ www_dir }}" -not -user "{{ user }}" -o -not -group "{{ apache_user }}" 9 | register: var_www_permissions 10 | when: www_dir_exists.stat.exists == true 11 | changed_when: var_www_permissions.stdout != "" 12 | 13 | - name: "PREP: Ensure /var/www has correct permissions recursively" 14 | file: 15 | path: "{{ www_dir }}" 16 | owner: "{{ user }}" 17 | group: "{{ apache_user }}" 18 | mode: g+s 19 | recurse: yes 20 | when: www_dir_exists.stat.exists == true and var_www_permissions.stdout != "" 21 | -------------------------------------------------------------------------------- /app/orchestration/plays/db/adminer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "ADMINER: Check if software is installed" 3 | stat: 4 | path: "{{ adminer_index }}" 5 | register: adminer 6 | ignore_errors: True 7 | 8 | - name: "ADMINER: Check version" 9 | shell: grep -o "version {{ adminer_stable_release }}" {{ adminer_index }} || echo "update" 10 | register: adminer_release 11 | when: adminer.stat.exists == true 12 | changed_when: adminer_release == "update" 13 | 14 | - name: "ADMINER: Create adminer directory" 15 | file: 16 | path: "{{ adminer_root }}" 17 | state: directory 18 | mode: 0755 19 | owner: "{{ user }}" 20 | group: "{{ apache_user }}" 21 | when: adminer.stat.exists == false 22 | 23 | - name: "ADMINER: Copy latest release from mirror" 24 | get_url: 25 | url: "{{ adminer_mirror_download_link }}" 26 | dest: "{{ adminer_root }}" 27 | validate_certs: no 28 | register: adminer_get_url_result 29 | until: "'OK' in adminer_get_url_result.msg" 30 | retries: 3 31 | delay: 10 32 | when: adminer.stat.exists == false or adminer_release.stdout == "update" 33 | 34 | - name: "ADMINER: Rename file" 35 | command: mv {{ adminer_root }}/adminer-{{ adminer_stable_release }}-en.php {{ adminer_index }} 36 | when: adminer.stat.exists == false or adminer_release.stdout == "update" 37 | 38 | - name: "ADMINER: Ensure permissions are correct" 39 | file: 40 | path: "{{ adminer_index }}" 41 | owner: "{{ user }}" 42 | group: "{{ apache_user }}" 43 | when: adminer.stat.exists == false or adminer_release.stdout == "update" 44 | 45 | - name: "ADMINER: Check if vHost exists" 46 | stat: 47 | path: "{{ adminer_vhost }}" 48 | register: adminer_conf 49 | ignore_errors: True 50 | 51 | - name: "ADMINER: Deploy default vHost template" 52 | copy: 53 | src: "{{ source_file_dir}}/apache-template.conf" 54 | dest: "{{ sites_available }}" 55 | mode: 0644 56 | when: adminer_conf.stat.exists == false 57 | 58 | - name: "ADMINER: Rename default vHost template" 59 | command: mv {{ vhost_template }} {{ adminer_available_vhost }} 60 | when: adminer_conf.stat.exists == false 61 | 62 | - name: "ADMINER: Add support for php-fpm Fast-CGI" 63 | blockinfile: 64 | dest: "{{ adminer_available_vhost }}" 65 | block: |6 66 | ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/var/run/php/php{{ default_php_version }}-fpm.sock|fcgi://127.0.0.1:9000/var/www/html/adminer/ 67 | insertafter: '^(.*)DocumentRoot(.*)$' 68 | marker: "# {mark} MANAGED PHP-FPM FAST-CGI BLOCK" 69 | when: adminer_conf.stat.exists == false 70 | 71 | - name: "ADMINER: Modify vHost 1/2" 72 | replace: 73 | dest: "{{ adminer_available_vhost }}" 74 | regexp: '^(.*)SITENAME\/docroot(.*)$' 75 | replace: '\1adminer\2' 76 | when: adminer_conf.stat.exists == false 77 | 78 | - name: "ADMINER: Modify vHost 2/2" 79 | replace: 80 | dest: "{{ adminer_available_vhost }}" 81 | regexp: '^(.*)SITENAME(.*)$' 82 | replace: '\1adminer\2' 83 | when: adminer_conf.stat.exists == false 84 | 85 | - name: "ADMINER: Enable vHost" 86 | file: 87 | src: ../sites-available/adminer.conf 88 | dest: "{{ adminer_vhost }}" 89 | state: link 90 | notify: Reload Apache 91 | when: adminer_conf.stat.exists == false 92 | -------------------------------------------------------------------------------- /app/orchestration/plays/db/db-tools.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MEMCACHED: Install libmemcached-tools package" 3 | package: 4 | # Provides memcstat. 5 | name: libmemcached-tools 6 | state: present 7 | 8 | - name: "MYSQL: Ensure we can manage remote MySQL databases" 9 | package: 10 | name: "{{ item }}" 11 | state: present 12 | with_items: 13 | - python-mysqldb 14 | - mysql-client 15 | 16 | - import_tasks: phpmyadmin.yml 17 | - import_tasks: adminer.yml 18 | -------------------------------------------------------------------------------- /app/orchestration/plays/db/memcached.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MEMCACHED: Install software" 3 | package: 4 | name: "{{ item }}" 5 | state: present 6 | with_items: 7 | - memcached 8 | 9 | - name: "MEMCACHED: Check if daemon is started" 10 | shell: pgrep memcached || echo "not started" 11 | register: memcached_status 12 | changed_when: memcached_status.stdout == "not started" 13 | 14 | - name: "MEMCACHED: Start the daemon" 15 | command: memcached -d -u nobody -m 64 -p 11211 127.0.0.1 16 | when: memcached_status.stdout == "not started" 17 | -------------------------------------------------------------------------------- /app/orchestration/plays/db/mysql-backup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MYSQL: Check if backup directory exists" 3 | stat: 4 | path: "{{ db_backup_dir }}" 5 | register: backup_dir 6 | changed_when: backup_dir.stat.exists == false 7 | 8 | - name: "MYSQL: Create backup directory" 9 | file: 10 | path: "{{ db_backup_dir }}" 11 | state: directory 12 | when: backup_dir.stat.exists == false 13 | 14 | - name: "MYSQL: Check if backup script exists" 15 | stat: 16 | path: "{{ db_backup_path }}" 17 | register: mysql_backup_check 18 | changed_when: mysql_backup_check.stat.exists == false 19 | 20 | - name: "MYSQL: Deploy backup script" 21 | copy: 22 | src: "{{ db_backup_source_file }}" 23 | dest: "{{ user_programs_path }}" 24 | mode: 0755 25 | when: mysql_backup_check.stat.exists == false 26 | 27 | - name: "MYSQL: Schedule periodic backups" 28 | cron: 29 | name: "Hourly MySQL backup for all databases" 30 | job: "{{ db_backup_path }}" 31 | user: root 32 | minute: "02" 33 | state: present 34 | 35 | - name: "MYSQL: Schedule periodic backup cleanup" 36 | cron: 37 | name: "Clean up MySQL backups every 3 hours" 38 | job: /usr/bin/find {{ db_backup_dir }} -mmin +180 -name "*.gz" -exec rm -f {} \; 39 | user: root 40 | minute: "05" 41 | state: present 42 | 43 | - name: "MYSQL: Restart cron to take into account new crontab" 44 | service: 45 | name: cron 46 | enabled: yes 47 | state: restarted 48 | -------------------------------------------------------------------------------- /app/orchestration/plays/db/mysql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MYSQL: Check if server is installed" 3 | stat: 4 | path: "{{ db_config }}" 5 | register: mariadb 6 | ignore_errors: True 7 | 8 | - name: "MYSQL: Clean up data directory" 9 | shell: rm -Rf {{ db_data }}/* 10 | args: 11 | warn: no 12 | when: mariadb.stat.exists == false 13 | 14 | - name: "MYSQL: Install server and utilities" 15 | package: 16 | name: "{{ item }}" 17 | state: present 18 | force: yes 19 | with_items: 20 | - mariadb-server 21 | - python-mysqldb 22 | when: mariadb.stat.exists == false 23 | 24 | - name: "MYSQL: Set innodb_file_per_table" 25 | blockinfile: 26 | dest: "{{ db_config }}" 27 | block: | 28 | innodb_file_per_table = 1 29 | insertafter: '^\[mysqld\]' 30 | marker: "# {mark} MANAGED INNODB BLOCK" 31 | when: mariadb.stat.exists == false 32 | 33 | - name: "MYSQL: Check if server is configured to allow remote access" 34 | shell: grep -o "0.0.0.0" {{ db_config }} || echo "denied" 35 | register: db_config_remote_access 36 | changed_when: db_config_remote_access == "denied" 37 | 38 | - name: "MYSQL: Configure server to allow remote access" 39 | replace: 40 | dest: "{{ db_config }}" 41 | regexp: '^(.*)127.0.0.1(.*)$' 42 | replace: '\1 0.0.0.0\2' 43 | when: db_config_remote_access.stdout == "denied" 44 | 45 | # Permissions can randomly be messed up so we're fixing them every time we get 46 | # the chance. 47 | - name: "MYSQL: Set correct permissions and ownership" 48 | file: 49 | path: "{{ db_data }}" 50 | owner: mysql 51 | group: mysql 52 | mode: 0755 53 | 54 | - name: "MYSQL: Start server" 55 | service: 56 | name: "{{ item }}" 57 | state: started 58 | enabled: yes 59 | with_items: 60 | - mysql 61 | when: mariadb.stat.exists == false 62 | 63 | - name: "MYSQL: Set root user password" 64 | mysql_user: 65 | login_user: "{{ db_creds }}" 66 | login_password: "{{ db_creds }}" 67 | name: "{{ db_creds }}" 68 | password: "{{ db_creds }}" 69 | check_implicit_admin: yes 70 | state: present 71 | when: mariadb.stat.exists == false 72 | 73 | - name: "MYSQL: Ensure server is started" 74 | service: 75 | name: mysql 76 | enabled: yes 77 | state: started 78 | 79 | - name: "MYSQL: Grant remote user access to all databases" 80 | mysql_user: 81 | login_user: "{{ db_creds }}" 82 | login_password: "{{ db_creds }}" 83 | login_host: localhost 84 | name: "{{ db_creds }}" 85 | password: "{{ db_creds }}" 86 | priv: "*.*:ALL" 87 | host: "{{ web_ip }}" 88 | state: present 89 | 90 | - name: "MYSQL: Ensure server is restarted" 91 | service: 92 | name: mysql 93 | enabled: yes 94 | state: restarted 95 | -------------------------------------------------------------------------------- /app/orchestration/plays/drupal/drupal-create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - vars.yml 8 | handlers: 9 | - import_tasks: handlers.yml 10 | tasks: 11 | - import_tasks: plays/drupal/drupal-create.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/plays/drupal/drupal-tools.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_tasks: ../tools/drush.yml 3 | - import_tasks: ../tools/drupal-console.yml 4 | -------------------------------------------------------------------------------- /app/orchestration/plays/drupal/drupal.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - import_tasks: ../app/drupal.yml 3 | vars: 4 | sitename: "drucker" 5 | -------------------------------------------------------------------------------- /app/orchestration/plays/edge/nginx.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "NGINX: Check if server is installed" 3 | stat: 4 | path: "{{ nginx_conf }}" 5 | register: nginx 6 | ignore_errors: True 7 | 8 | - name: "NGINX: Install server" 9 | package: 10 | name: "{{ item }}" 11 | state: present 12 | update_cache: yes 13 | with_items: 14 | - nginx 15 | when: nginx.stat.exists == false 16 | 17 | - name: "NGINX: Check if default site exists" 18 | stat: 19 | path: "{{ nginx_default_site }}" 20 | register: nginx_default 21 | ignore_errors: True 22 | 23 | - name: "NGINX: Delete default site" 24 | file: 25 | path: "{{ nginx_default_site }}" 26 | state: absent 27 | when: nginx_default.stat.exists == true 28 | 29 | - name: "NGINX: Check if default site configuration exists" 30 | stat: 31 | path: "{{ nginx_default_conf }}" 32 | register: nginx_default_configuration 33 | ignore_errors: True 34 | 35 | - name: "NGINX: Delete default site configuration" 36 | file: 37 | path: "{{ nginx_default_conf }}" 38 | state: absent 39 | when: nginx_default_configuration.stat.exists == true 40 | 41 | - name: "NGINX: Check if drucker host exists" 42 | stat: 43 | path: "{{ drucker_nginx_vhost }}" 44 | register: nginx_drucker_host 45 | ignore_errors: True 46 | 47 | - name: "NGINX: Deploy template" 48 | copy: 49 | src: "{{ nginx_template_source_file }}" 50 | dest: "{{ nginx_conf_dir }}" 51 | mode: 0644 52 | when: nginx_drucker_host.stat.exists == false 53 | 54 | - name: "NGINX: Rename template" 55 | command: mv {{ nginx_default_template }} {{ drucker_nginx_vhost }} 56 | when: nginx_drucker_host.stat.exists == false 57 | 58 | - name: "NGINX: Modify proxy_pass" 59 | replace: 60 | dest: "{{ drucker_nginx_vhost }}" 61 | regexp: '^(.*)proxy_pass http://0.0.0.0:{{ edge_port }};(.*)$' 62 | replace: '\1proxy_pass http://{{ web_ip }}:{{ edge_port }};\2' 63 | when: nginx_drucker_host.stat.exists == false 64 | 65 | - name: "NGINX: Increase client_max_body_size" 66 | lineinfile: 67 | dest: "{{ nginx_conf }}" 68 | insertafter: '^(.*)sendfile on;(.*)$' 69 | line: " client_max_body_size {{ client_max_body_size }};" 70 | 71 | - name: "NGINX: Support fake SSL" 72 | copy: 73 | src: "{{ ssl_source_dir }}" 74 | dest: "{{ nginx_conf_dir }}" 75 | mode: 0755 76 | when: nginx_drucker_host.stat.exists == false 77 | 78 | - name: "NGINX: Ensure server starts on boot" 79 | service: 80 | name: nginx 81 | enabled: yes 82 | when: nginx_drucker_host.stat.exists == false 83 | 84 | - name: "NGINX: Check if server is started" 85 | shell: pgrep nginx || echo 'down' 86 | register: check_nginx_up 87 | changed_when: check_nginx_up.stdout == "down" 88 | 89 | - name: "NGINX: Ensure server is started" 90 | command: /etc/init.d/nginx start 91 | become: yes 92 | when: check_nginx_up.stdout == "down" 93 | -------------------------------------------------------------------------------- /app/orchestration/plays/edge/varnish.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "VARNISH: Check if server is installed" 3 | stat: 4 | path: "{{ varnish_config }}" 5 | register: varnish 6 | ignore_errors: True 7 | 8 | - name: "VARNISH: Install server" 9 | package: 10 | name: "{{ item }}" 11 | state: present 12 | update_cache: yes 13 | with_items: 14 | - varnish 15 | when: varnish.stat.exists == false 16 | 17 | - name: "VARNISH: Deploy configuration template" 18 | copy: 19 | src: "{{ varnish_conf_source_file }}" 20 | dest: /etc/default/ 21 | mode: 0644 22 | when: varnish.stat.exists == false 23 | 24 | - name: "VARNISH: Deploy default VCL template" 25 | copy: 26 | src: "{{ varnish_default_vcl_source_file}}" 27 | dest: "{{ varnish_default_path }}" 28 | mode: 0644 29 | when: varnish.stat.exists == false 30 | 31 | - name: "VARNISH: Ensure server is started" 32 | service: 33 | name: varnish 34 | enabled: yes 35 | state: started 36 | -------------------------------------------------------------------------------- /app/orchestration/plays/mirror/mirror-setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "APT-CACHER-NG: Check if APT cache mirror exists" 3 | stat: 4 | path: "{{ mirror_cache_dir }}" 5 | register: mirror_cache_dir_check 6 | changed_when: mirror_cache_dir_check.stat.exists == false 7 | 8 | - name: "APT-CACHER-NG: Install APT cache mirror" 9 | package: 10 | name: apt-cacher-ng 11 | state: present 12 | force: yes 13 | when: mirror_cache_dir_check.stat.exists == false 14 | 15 | - name: "APT-CACHER-NG: Check if the APT mirror is configured to allow remote access" 16 | shell: grep -o "BindAddress:\ 0.0.0.0" {{ mirror_config }} || echo "denied" 17 | register: mirror_remote_access 18 | changed_when: mirror_remote_access.stdout == "denied" 19 | 20 | - name: "APT-CACHER-NG: Configure the APT mirror to allow remote access" 21 | lineinfile: 22 | dest: "{{ mirror_config }}" 23 | line: "BindAddress: 0.0.0.0" 24 | insertafter: EOF 25 | when: mirror_remote_access.stdout == "denied" 26 | 27 | - name: "APT-CACHER-NG: Check if the APT mirror is configured to run as a service" 28 | shell: grep -o "# PidFile" {{ mirror_config }} || echo "configured" 29 | register: mirror_service 30 | changed_when: mirror_service.stdout != "configured" 31 | 32 | - name: "APT-CACHER-NG: Enable the APT mirror to run as a service" 33 | lineinfile: 34 | dest: "{{ mirror_config }}" 35 | regexp: "# PidFile: /var/run/apt-cacher-ng/pid" 36 | line: "PidFile: /var/run/apt-cacher-ng/pid" 37 | when: mirror_service.stdout != "configured" 38 | 39 | - name: "APT-CACHER-NG: Check if the APT mirror is configured to run as a service" 40 | shell: grep -E "^PassThroughPattern:\ .*" {{ mirror_config }} || echo "not configured" 41 | register: passthrough 42 | changed_when: passthrough.stdout == "not configured" 43 | 44 | - name: "APT-CACHER-NG: Enable SSL/TLS support" 45 | lineinfile: 46 | dest: "{{ mirror_config }}" 47 | line: "PassThroughPattern: .*" 48 | insertafter: "^# PassThroughPattern: .* # this would allow CONNECT to everything" 49 | when: passthrough.stdout == "not configured" 50 | 51 | - name: "APT-CACHER-NG: Restart APT mirror service" 52 | service: 53 | name: apt-cacher-ng 54 | enabled: yes 55 | state: restarted 56 | when: mirror_cache_dir_check.stat.exists == false 57 | 58 | - import_tasks: ../common/apt-update.yml 59 | 60 | - name: "SYSTEM: Ensure Apache is started" 61 | service: 62 | name: apache2 63 | enabled: yes 64 | state: started 65 | 66 | - name: "APT-CACHER-NG: Ensure APT mirror service is started" 67 | service: 68 | name: apt-cacher-ng 69 | enabled: yes 70 | state: started 71 | -------------------------------------------------------------------------------- /app/orchestration/plays/mirror/mirror-vhost.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "APACHE: Check if new vHost exists" 3 | stat: 4 | path: "{{ sites_enabled }}/{{ mirror_conf }}" 5 | register: mirror_vhost_check 6 | ignore_errors: True 7 | 8 | - name: "APACHE: Delete default vHost" 9 | file: 10 | path: "{{ item }}" 11 | state: absent 12 | with_items: 13 | - "{{ default_vhost }}" 14 | - "{{ default_available_vhost }}" 15 | when: mirror_vhost_check.stat.exists == false 16 | 17 | - name: "APACHE: Deploy default vHost template" 18 | copy: 19 | src: "{{ apache_template_source_file }}" 20 | dest: "{{ sites_available }}" 21 | mode: 0644 22 | when: mirror_vhost_check.stat.exists == false 23 | 24 | - name: "APACHE: Rename default vHost template" 25 | command: mv {{ vhost_template }} {{ sites_available }}/{{ mirror_conf }} 26 | when: mirror_vhost_check.stat.exists == false 27 | 28 | - name: "APACHE: Modify new vHost 1/2" 29 | replace: 30 | dest: "{{ sites_available }}/{{ mirror_conf }}" 31 | regexp: '^(.*)/var/www/html/SITENAME/docroot(.*)$' 32 | replace: '\1{{ mirror_archives_dir }}\2' 33 | when: mirror_vhost_check.stat.exists == false 34 | 35 | - name: "APACHE: Modify new vHost 2/2" 36 | replace: 37 | dest: "{{ sites_available }}/{{ mirror_conf }}" 38 | regexp: '^(.*)SITENAME(.*)$' 39 | replace: '\1mirror\2' 40 | when: mirror_vhost_check.stat.exists == false 41 | 42 | - name: "APACHE: Enable new vHost" 43 | file: 44 | src: ../sites-available/{{ mirror_conf }} 45 | dest: "{{ sites_enabled }}/{{ mirror_conf }}" 46 | state: link 47 | force: yes 48 | register: test 49 | notify: Reload Apache 50 | when: mirror_vhost_check.stat.exists == false 51 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/default-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if the version file exists" 3 | stat: 4 | path: "{{ default_php_version_file }}" 5 | register: php_version_file_check 6 | 7 | - name: "PHP: Check which PHP version is currently running" 8 | shell: grep -o "{{ default_php_version }}" {{ default_php_version_file }} || echo "Different version" 9 | register: current_php 10 | when: php_version_file_check.stat.exists == true 11 | 12 | - name: "PHP: Check if PHP {{ default_php_version }} is installed" 13 | stat: 14 | path: "{{ default_php_ini }}" 15 | register: default_phpfpm 16 | 17 | - name: "PHP: Install PHP {{ default_php_version }} core packages" 18 | package: 19 | name: "{{ item }}" 20 | state: present 21 | with_items: 22 | - php{{ default_php_version }}-fpm 23 | - php{{ default_php_version }}-cli 24 | - php{{ default_php_version }}-common 25 | - php{{ default_php_version }}-dev 26 | when: default_phpfpm.stat.exists == false 27 | 28 | - name: "PHP: Write default PHP version to file" 29 | copy: 30 | content: "{{ default_php_version }}" 31 | dest: "{{ default_php_version_file }}" 32 | when: php_version_file_check.stat.exists == false 33 | 34 | - name: "PHP: Install PHP {{ default_php_version }} extensions" 35 | package: 36 | name: "{{ item }}" 37 | state: present 38 | with_items: 39 | - php-imagick 40 | - php-memcached 41 | - php{{ default_php_version }}-apcu 42 | - php{{ default_php_version }}-curl 43 | - php{{ default_php_version }}-gd 44 | - php{{ default_php_version }}-mbstring 45 | - php{{ default_php_version }}-mysql 46 | - php{{ default_php_version }}-xmlrpc 47 | - php{{ default_php_version }}-xsl 48 | - php{{ default_php_version }}-bz2 49 | - php{{ default_php_version }}-sqlite3 50 | when: default_phpfpm.stat.exists == false 51 | 52 | - name: "PHP: Ensure PHP {{ default_php_version }} extensions directory exists" 53 | file: 54 | path: "{{ default_php_extensions }}" 55 | state: directory 56 | when: default_phpfpm.stat.exists == false 57 | 58 | - import_tasks: php_version_and_vhost_check.yml 59 | 60 | - name: "PHP: Update PHP FPM version in vHosts" 61 | replace: 62 | dest: "{{ item }}" 63 | regexp: '^(.*)php{{ php_read_version.stdout }}-fpm.sock(.*)$' 64 | replace: '\1php{{ default_php_version }}-fpm.sock\2' 65 | with_items: 66 | - "{{ apache_vhosts_list.stdout_lines }}" 67 | when: apache_vhosts_list.stdout != 'no vHost' 68 | 69 | - name: "PHP: Switch PHP CLI version" 70 | command: update-alternatives --set php /usr/bin/php{{ default_php_version }} 71 | 72 | - import_tasks: phpfpm_process_check.yml 73 | 74 | - name: "PHP: Start PHP {{ default_php_version }} FPM" 75 | command: /etc/init.d/php{{ default_php_version }}-fpm start 76 | when: default_php_version != php_read_version.stdout or phpfpm_is_started.stdout == 'stopped' 77 | 78 | - name: "PHP: Ensure PHP {{ default_php_version }} is started" 79 | shell: pgrep -ln php-fpm | awk '{print $NF}' 80 | register: default_phpfpm_is_started 81 | notify: Restart Apache 82 | 83 | - name: "PHP: Write new version to file" 84 | copy: 85 | content: "{{ default_php_version }}" 86 | dest: "{{ default_php_version_file }}" 87 | 88 | - import_tasks: default_php_ini.yml 89 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/default_php_ini.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Increase max_input_time" 3 | lineinfile: 4 | dest: "{{ default_php_ini }}" 5 | regexp: "max_input_time = 60" 6 | line: "max_input_time = {{ max_input_time }}" 7 | when: default_phpfpm.stat.exists == false 8 | 9 | - name: "PHP: Increase max_execution_time" 10 | lineinfile: 11 | dest: "{{ default_php_ini }}" 12 | regexp: "max_execution_time = 30" 13 | line: "max_execution_time = {{ max_execution_time }}" 14 | when: default_phpfpm.stat.exists == false 15 | 16 | - name: "PHP: Increase memory_limit" 17 | lineinfile: 18 | dest: "{{ default_php_ini }}" 19 | regexp: "memory_limit = 128M" 20 | line: "memory_limit = {{ memory_limit }}" 21 | when: default_phpfpm.stat.exists == false 22 | 23 | - name: "PHP: Increase upload_max_filesize" 24 | lineinfile: 25 | dest: "{{ default_php_ini }}" 26 | regexp: "upload_max_filesize = 2M" 27 | line: "upload_max_filesize = {{ upload_max_filesize }}" 28 | when: default_phpfpm.stat.exists == false 29 | 30 | - name: "PHP: Increase max_file_uploads" 31 | lineinfile: 32 | dest: "{{ default_php_ini }}" 33 | regexp: "max_file_uploads = 20" 34 | line: "max_file_uploads = {{ max_file_uploads }}" 35 | when: default_phpfpm.stat.exists == false 36 | 37 | - name: "PHP: Increase post_max_size" 38 | lineinfile: 39 | dest: "{{ default_php_ini }}" 40 | regexp: "post_max_size = 8M" 41 | line: "post_max_size = {{ post_max_size }}" 42 | when: default_phpfpm.stat.exists == false 43 | 44 | - name: "PHP: Increase opcache.max_accelerated_files" 45 | lineinfile: 46 | dest: "{{ default_php_ini }}" 47 | regexp: ";opcache.max_accelerated_files=2000" 48 | line: "opcache.max_accelerated_files={{ opcache_max_accelerated_files }}" 49 | when: default_phpfpm.stat.exists == false 50 | 51 | - name: "PHP: Turn off Zend assertions" 52 | replace: 53 | dest: "{{ default_php_ini }}" 54 | regexp: '^(.*)zend.assertions = 1(.*)$' 55 | replace: '\1zend.assertions = -1\2' 56 | when: default_phpfpm.stat.exists == false 57 | 58 | - name: "PHP: Add default timezone" 59 | lineinfile: 60 | dest: "{{ default_php_ini_cli }}" 61 | regexp: ";date.timezone =" 62 | line: "date.timezone = {{ timezone }}" 63 | notify: Restart Apache 64 | when: default_phpfpm.stat.exists == false 65 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/legacy-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if the version file exists" 3 | stat: 4 | path: "{{ default_php_version_file }}" 5 | register: php_version_file_check 6 | 7 | - name: "PHP: Check which PHP version is currently running" 8 | shell: grep -o "{{ legacy_php_version }}" {{ default_php_version_file }} || echo "Different version" 9 | when: php_version_file_check.stat.exists == true 10 | register: current_php 11 | 12 | - name: "PHP: Check if PHP {{ legacy_php_version}} is installed" 13 | stat: 14 | path: "{{ legacy_php_ini }}" 15 | register: legacy_phpfpm 16 | 17 | - name: "PHP: Install PHP {{ legacy_php_version}} core packages" 18 | package: 19 | name: "{{ item }}" 20 | state: present 21 | with_items: 22 | - php{{ legacy_php_version }}-fpm 23 | - php{{ legacy_php_version }}-cli 24 | - php{{ legacy_php_version }}-common 25 | - php{{ legacy_php_version }}-dev 26 | when: legacy_phpfpm.stat.exists == false 27 | 28 | - name: "PHP: Install PHP {{ legacy_php_version}} extensions" 29 | package: 30 | name: "{{ item }}" 31 | state: present 32 | with_items: 33 | - php-imagick 34 | - php-memcached 35 | - php{{ legacy_php_version }}-apcu 36 | - php{{ legacy_php_version }}-curl 37 | - php{{ legacy_php_version }}-gd 38 | - php{{ legacy_php_version }}-mbstring 39 | - php{{ legacy_php_version }}-mysql 40 | - php{{ legacy_php_version }}-xmlrpc 41 | - php{{ legacy_php_version }}-xsl 42 | - php{{ legacy_php_version }}-bz2 43 | - php{{ legacy_php_version }}-sqlite3 44 | when: legacy_phpfpm.stat.exists == false 45 | 46 | - name: "PHP: Ensure PHP {{ legacy_php_version }} extensions directory exists" 47 | file: 48 | path: "{{ legacy_php_extensions }}" 49 | state: directory 50 | when: legacy_phpfpm.stat.exists == false 51 | 52 | - import_tasks: php_version_and_vhost_check.yml 53 | 54 | - name: "PHP: Update PHP FPM version in vHosts" 55 | replace: 56 | dest: "{{ item }}" 57 | regexp: '^(.*)php{{ php_read_version.stdout }}-fpm.sock(.*)$' 58 | replace: '\1php{{ legacy_php_version }}-fpm.sock\2' 59 | with_items: 60 | - "{{ apache_vhosts_list.stdout_lines }}" 61 | when: apache_vhosts_list.stdout != 'no vHost' 62 | 63 | - name: "PHP: Switch PHP CLI version" 64 | command: update-alternatives --set php /usr/bin/php{{ legacy_php_version }} 65 | 66 | - import_tasks: phpfpm_process_check.yml 67 | 68 | - name: "PHP: Start PHP {{ legacy_php_version}} FPM" 69 | command: /etc/init.d/php{{ legacy_php_version }}-fpm start 70 | when: legacy_php_version != php_read_version.stdout or phpfpm_is_started.stdout == 'stopped' 71 | 72 | - name: "PHP: Ensure PHP {{ legacy_php_version}} FPM is started" 73 | shell: pgrep -ln php-fpm | awk '{print $NF}' 74 | register: legacy_phpfpm_is_started 75 | notify: Restart Apache 76 | 77 | - name: "PHP: Write new PHP version to file" 78 | copy: 79 | content: "{{ legacy_php_version }}" 80 | dest: "{{ default_php_version_file }}" 81 | when: legacy_phpfpm_is_started.changed 82 | 83 | - import_tasks: legacy_php_ini.yml 84 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/legacy_php_ini.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Increase max_input_time" 3 | lineinfile: 4 | dest: "{{ legacy_php_ini }}" 5 | regexp: "max_input_time = 60" 6 | line: "max_input_time = {{ max_input_time }}" 7 | when: legacy_phpfpm.stat.exists == false 8 | 9 | - name: "PHP: Increase max_execution_time" 10 | lineinfile: 11 | dest: "{{ legacy_php_ini }}" 12 | regexp: "max_execution_time = 30" 13 | line: "max_execution_time = {{ max_execution_time }}" 14 | when: legacy_phpfpm.stat.exists == false 15 | 16 | - name: "PHP: Increase memory_limit" 17 | lineinfile: 18 | dest: "{{ legacy_php_ini }}" 19 | regexp: "memory_limit = 128M" 20 | line: "memory_limit = {{ memory_limit }}" 21 | when: legacy_phpfpm.stat.exists == false 22 | 23 | - name: "PHP: Increase upload_max_filesize" 24 | lineinfile: 25 | dest: "{{ legacy_php_ini }}" 26 | regexp: "upload_max_filesize = 2M" 27 | line: "upload_max_filesize = {{ upload_max_filesize }}" 28 | when: legacy_phpfpm.stat.exists == false 29 | 30 | - name: "PHP: Increase max_file_uploads" 31 | lineinfile: 32 | dest: "{{ legacy_php_ini }}" 33 | regexp: "max_file_uploads = 20" 34 | line: "max_file_uploads = {{ max_file_uploads }}" 35 | when: legacy_phpfpm.stat.exists == false 36 | 37 | - name: "PHP: Increase post_max_size" 38 | lineinfile: 39 | dest: "{{ legacy_php_ini }}" 40 | regexp: "post_max_size = 8M" 41 | line: "post_max_size = {{ post_max_size }}" 42 | when: legacy_phpfpm.stat.exists == false 43 | 44 | - name: "PHP: Increase opcache.max_accelerated_files" 45 | lineinfile: 46 | dest: "{{ legacy_php_ini }}" 47 | regexp: ";opcache.max_accelerated_files=2000" 48 | line: "opcache.max_accelerated_files={{ opcache_max_accelerated_files }}" 49 | when: legacy_phpfpm.stat.exists == false 50 | 51 | - name: "PHP: Add default timezone" 52 | lineinfile: 53 | dest: "{{ legacy_php_ini_cli }}" 54 | regexp: ";date.timezone =" 55 | line: "date.timezone = {{ timezone }}" 56 | notify: Restart Apache 57 | when: legacy_phpfpm.stat.exists == false 58 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/libyaml.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "LIBYAML: Install required build tools" 3 | package: 4 | name: "{{ item }}" 5 | state: present 6 | with_items: 7 | - build-essential 8 | - autogen 9 | - autoconf 10 | - libtool 11 | 12 | - name: "LIBYAML: Check if archive exists" 13 | stat: 14 | path: "{{ libyaml_archive_path }}" 15 | register: libyaml_archive 16 | 17 | - name: "LIBYAML: Copy latest release from mirror" 18 | get_url: 19 | url: "{{ libyaml_mirror_download_link }}" 20 | dest: "{{ download_dir }}" 21 | validate_certs: no 22 | register: libyaml_get_url_result 23 | until: "'OK' in libyaml_get_url_result.msg" 24 | retries: 3 25 | delay: 10 26 | when: libyaml_archive.stat.exists == false 27 | changed_when: libyaml_archive.stat.exists == false 28 | 29 | - name: "LIBYAML: Extract files" 30 | unarchive: 31 | src: "{{ libyaml_archive_path }}" 32 | dest: "{{ download_dir }}" 33 | copy: no 34 | when: libyaml_archive.stat.exists == false 35 | 36 | - name: "LIBYAML: Compile parser" 37 | command: "{{ item }} chdir={{ libyaml_temp_path }}" 38 | with_items: 39 | - ./bootstrap 40 | - ./configure 41 | - /usr/bin/make 42 | - /usr/bin/make install 43 | when: libyaml_archive.stat.exists == false 44 | 45 | - name: "LIBYAML: Delete temporary parser directory" 46 | file: 47 | path: "{{ libyaml_temp_path }}" 48 | state: absent 49 | when: libyaml_archive.stat.exists == false 50 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/pecl-yaml.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # See change record: https://www.drupal.org/node/2769555 3 | - name: "PECL YAML: Check if the extension is installed" 4 | stat: 5 | path: "{{ pecl_yaml_extension_path }}" 6 | register: pecl_yaml_extension_check 7 | 8 | - name: "PECL YAML: Copy latest release from mirror" 9 | get_url: 10 | url: "{{ pecl_yaml_mirror_download_link }}" 11 | dest: "{{ download_dir }}" 12 | validate_certs: no 13 | register: pecl_yaml_get_url_result 14 | until: "'OK' in pecl_yaml_get_url_result.msg" 15 | retries: 3 16 | delay: 10 17 | when: pecl_yaml_extension_check.stat.exists == false 18 | 19 | - name: "PECL YAML: Extract files" 20 | unarchive: 21 | src: "{{ pecl_yaml_archive }}" 22 | dest: "{{ download_dir }}" 23 | copy: no 24 | when: pecl_yaml_extension_check.stat.exists == false 25 | 26 | - name: "PECL YAML: Compile extension" 27 | command: "{{ item }} chdir={{ pecl_yaml_temp_path }}" 28 | with_items: 29 | - /usr/bin/phpize 30 | - ./configure 31 | - /usr/bin/make 32 | - /usr/bin/make install 33 | when: pecl_yaml_extension_check.stat.exists == false 34 | 35 | - name: "PECL YAML: Copy compiled extension" 36 | command: cp {{ pecl_yaml_temp_path }}/modules/{{ pecl_yaml_extension_name }} {{ default_php_extensions }} 37 | when: pecl_yaml_extension_check.stat.exists == false 38 | 39 | - name: "PECL YAML: Make sure permissions are correct" 40 | file: 41 | path: "{{ pecl_yaml_extension_path }}" 42 | mode: 0644 43 | when: pecl_yaml_extension_check.stat.exists == false 44 | 45 | - name: "PECL YAML: Delete temporary directory" 46 | file: 47 | path: "{{ pecl_yaml_temp_path }}" 48 | state: absent 49 | when: pecl_yaml_extension_check.stat.exists == false 50 | 51 | - name: "PECL YAML: Check config in php.ini" 52 | shell: grep -o "{{ pecl_yaml_extension_name }}" {{ default_php_ini }} || echo "absent" 53 | register: pecl_yaml_config 54 | changed_when: pecl_yaml_config.stdout == "absent" 55 | 56 | - name: "PECL YAML: Configure extension in php.ini" 57 | lineinfile: 58 | dest: "{{ default_php_ini }}" 59 | line: "extension={{ pecl_yaml_extension_path }}" 60 | when: pecl_yaml_config.stdout == "absent" 61 | 62 | - name: "PECL YAML: Ensure Apache is restarted to load the extension" 63 | service: 64 | name: apache2 65 | enabled: yes 66 | state: restarted 67 | 68 | - name: "PECL YAML: Ensure PHP-FPM is restarted to load the extension" 69 | service: 70 | name: php{{ default_php_version }}-fpm 71 | enabled: yes 72 | state: restarted 73 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if PHP is installed" 3 | stat: 4 | path: "{{ default_php_ini }}" 5 | register: phpfpm_is_installed 6 | 7 | - name: "PHP: Add deb.sury.org GPG signature" 8 | apt_key: 9 | url: "{{ sury_gpg }}" 10 | state: present 11 | validate_certs: no 12 | when: phpfpm_is_installed.stat.exists == false 13 | 14 | - name: "PHP: Add deb.sury.org repository" 15 | apt_repository: 16 | repo: "{{ sury_deb }}" 17 | state: present 18 | when: phpfpm_is_installed.stat.exists == false 19 | 20 | - name: "PHP: Update APT cache to load new repository" 21 | apt: 22 | update_cache: yes 23 | when: phpfpm_is_installed.stat.exists == false 24 | 25 | - import_tasks: default-php.yml 26 | 27 | - name: "PHP: Check if php7 module is enabled" 28 | stat: 29 | path: "{{ apache_php_mod }}" 30 | register: php7_module 31 | 32 | - name: "PHP: Disable php7 module" 33 | apache2_module: 34 | state: absent 35 | name: php7 36 | notify: Restart PHP-FPM 37 | when: php7_module.stat.exists == true 38 | 39 | - name: "PHP: Check if proxy_fcgi module is enabled" 40 | stat: 41 | path: "{{ apache_proxy_fcgi_mod }}" 42 | register: proxy_fcgi_module 43 | 44 | # php-fpm Fast-CGI support 45 | - name: "PHP: Enable proxy_fcgi module" 46 | apache2_module: 47 | state: present 48 | name: proxy_fcgi 49 | notify: Restart PHP-FPM 50 | when: proxy_fcgi_module.stat.exists == false 51 | 52 | - name: "PHP: Check if PHP FPM is started" 53 | shell: pgrep php-fpm || echo 'down' 54 | register: check_phpfpm_up 55 | changed_when: check_phpfpm_up.stdout == "down" 56 | 57 | - name: "PHP: Ensure PHP FPM is started" 58 | command: /etc/init.d/php{{ default_php_version }}-fpm start 59 | become: yes 60 | when: check_phpfpm_up.stdout == "down" 61 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/php_version_and_vhost_check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Store PHP version variable" 3 | shell: cat {{ default_php_version_file }} 4 | register: php_read_version 5 | 6 | - name: "APACHE: Retrieve existing vHosts" 7 | shell: ls {{ sites_available }}/*.conf | grep -Ev '(000-default|default-ssl.conf)' || echo 'no vHost' 8 | register: apache_vhosts_list 9 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/phpfpm_process_check.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if PHP FPM is already started" 3 | shell: pgrep -ln php-fpm | awk '{print $NF}' || echo 'stopped' 4 | register: phpfpm_is_started 5 | 6 | - name: "PHP: Stop current PHP FPM process" 7 | command: /etc/init.d/php{{ php_read_version.stdout }}-fpm stop 8 | when: phpfpm_is_started.stdout != 'stopped' 9 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/previous-php.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Check if the version file exists" 3 | stat: 4 | path: "{{ default_php_version_file }}" 5 | register: php_version_file_check 6 | 7 | - name: "PHP: Check which PHP version is currently running" 8 | shell: grep -o "{{ previous_php_version }}" {{ default_php_version_file }} || echo "Different version" 9 | when: php_version_file_check.stat.exists == true 10 | register: current_php 11 | 12 | - name: "PHP: Check if PHP {{ previous_php_version}} is installed" 13 | stat: 14 | path: "{{ previous_php_ini }}" 15 | register: previous_phpfpm 16 | 17 | - name: "PHP: Install PHP {{ previous_php_version}} core packages" 18 | package: 19 | name: "{{ item }}" 20 | state: present 21 | with_items: 22 | - php{{ previous_php_version }}-fpm 23 | - php{{ previous_php_version }}-cli 24 | - php{{ previous_php_version }}-common 25 | - php{{ previous_php_version }}-dev 26 | when: previous_phpfpm.stat.exists == false 27 | 28 | - name: "PHP: Install PHP {{ previous_php_version}} extensions" 29 | package: 30 | name: "{{ item }}" 31 | state: present 32 | with_items: 33 | - php-imagick 34 | - php-memcached 35 | - php{{ previous_php_version }}-apcu 36 | - php{{ previous_php_version }}-curl 37 | - php{{ previous_php_version }}-gd 38 | - php{{ previous_php_version }}-mbstring 39 | - php{{ previous_php_version }}-mysql 40 | - php{{ previous_php_version }}-xmlrpc 41 | - php{{ previous_php_version }}-xsl 42 | - php{{ previous_php_version }}-bz2 43 | - php{{ previous_php_version }}-sqlite3 44 | when: previous_phpfpm.stat.exists == false 45 | 46 | - name: "PHP: Ensure PHP {{ previous_php_version }} extensions directory exists" 47 | file: 48 | path: "{{ previous_php_extensions }}" 49 | state: directory 50 | when: previous_phpfpm.stat.exists == false 51 | 52 | - import_tasks: php_version_and_vhost_check.yml 53 | 54 | - name: "PHP: Update PHP FPM version in vHosts" 55 | replace: 56 | dest: "{{ item }}" 57 | regexp: '^(.*)php{{ php_read_version.stdout }}-fpm.sock(.*)$' 58 | replace: '\1php{{ previous_php_version }}-fpm.sock\2' 59 | with_items: 60 | - "{{ apache_vhosts_list.stdout_lines }}" 61 | when: apache_vhosts_list.stdout != 'no vHost' 62 | 63 | - name: "PHP: Switch PHP CLI version" 64 | command: update-alternatives --set php /usr/bin/php{{ previous_php_version }} 65 | 66 | - import_tasks: phpfpm_process_check.yml 67 | 68 | - name: "PHP: Start PHP {{ previous_php_version}} FPM" 69 | command: /etc/init.d/php{{ previous_php_version }}-fpm start 70 | when: previous_php_version != php_read_version.stdout or phpfpm_is_started.stdout == 'stopped' 71 | 72 | - name: "PHP: Ensure PHP {{ previous_php_version}} FPM is started" 73 | shell: pgrep -ln php-fpm | awk '{print $NF}' 74 | register: previous_phpfpm_is_started 75 | notify: Restart Apache 76 | 77 | - name: "PHP: Write new PHP version to file" 78 | copy: 79 | content: "{{ previous_php_version }}" 80 | dest: "{{ default_php_version_file }}" 81 | when: previous_phpfpm_is_started.changed 82 | 83 | - import_tasks: previous_php_ini.yml 84 | -------------------------------------------------------------------------------- /app/orchestration/plays/php/previous_php_ini.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP: Increase max_input_time" 3 | lineinfile: 4 | dest: "{{ previous_php_ini }}" 5 | regexp: "max_input_time = 60" 6 | line: "max_input_time = {{ max_input_time }}" 7 | when: previous_phpfpm.stat.exists == false 8 | 9 | - name: "PHP: Increase max_execution_time" 10 | lineinfile: 11 | dest: "{{ previous_php_ini }}" 12 | regexp: "max_execution_time = 30" 13 | line: "max_execution_time = {{ max_execution_time }}" 14 | when: previous_phpfpm.stat.exists == false 15 | 16 | - name: "PHP: Increase memory_limit" 17 | lineinfile: 18 | dest: "{{ previous_php_ini }}" 19 | regexp: "memory_limit = 128M" 20 | line: "memory_limit = {{ memory_limit }}" 21 | when: previous_phpfpm.stat.exists == false 22 | 23 | - name: "PHP: Increase upload_max_filesize" 24 | lineinfile: 25 | dest: "{{ previous_php_ini }}" 26 | regexp: "upload_max_filesize = 2M" 27 | line: "upload_max_filesize = {{ upload_max_filesize }}" 28 | when: previous_phpfpm.stat.exists == false 29 | 30 | - name: "PHP: Increase max_file_uploads" 31 | lineinfile: 32 | dest: "{{ previous_php_ini }}" 33 | regexp: "max_file_uploads = 20" 34 | line: "max_file_uploads = {{ max_file_uploads }}" 35 | when: previous_phpfpm.stat.exists == false 36 | 37 | - name: "PHP: Increase post_max_size" 38 | lineinfile: 39 | dest: "{{ previous_php_ini }}" 40 | regexp: "post_max_size = 8M" 41 | line: "post_max_size = {{ post_max_size }}" 42 | when: previous_phpfpm.stat.exists == false 43 | 44 | - name: "PHP: Increase opcache.max_accelerated_files" 45 | lineinfile: 46 | dest: "{{ previous_php_ini }}" 47 | regexp: ";opcache.max_accelerated_files=2000" 48 | line: "opcache.max_accelerated_files={{ opcache_max_accelerated_files }}" 49 | when: previous_phpfpm.stat.exists == false 50 | 51 | - name: "PHP: Add default timezone" 52 | lineinfile: 53 | dest: "{{ previous_php_ini_cli }}" 54 | regexp: ";date.timezone =" 55 | line: "date.timezone = {{ timezone }}" 56 | notify: Restart Apache 57 | when: previous_phpfpm.stat.exists == false 58 | -------------------------------------------------------------------------------- /app/orchestration/plays/post-install.yml: -------------------------------------------------------------------------------- 1 | - name: "POST-INSTALL: Check if all hostnames are configured" 2 | shell: grep -E '({{ phpmyadmin_hostname }}.{{ tld }}|{{ adminer_hostname }}.{{ tld }})' {{ hosts_file }} || echo "absent" 3 | register: additional_hostnames 4 | changed_when: additional_hostnames.stdout == "absent" 5 | 6 | - name: "POST-INSTALL: Make sure the web container can reach all hostnames" 7 | shell: echo "{{ web_ip }} {{ item }}.{{ tld }}" >> {{ hosts_file }} 8 | with_items: 9 | - "{{ phpmyadmin_hostname }}" 10 | - "{{ adminer_hostname }}" 11 | when: additional_hostnames.stdout == "absent" 12 | 13 | - name: "POST-INSTALL: Check if Solr hostname is configured" 14 | shell: grep -o "{{ search_ip }}" {{ hosts_file }} || echo "absent" 15 | register: search_hostname 16 | changed_when: search_hostname.stdout == "absent" 17 | 18 | - name: "POST-INSTALL: Make sure the web container can talk to the Solr backend" 19 | shell: echo "{{ search_ip }} search.{{ tld }}" >> {{ hosts_file }} 20 | when: search_hostname.stdout == "absent" 21 | -------------------------------------------------------------------------------- /app/orchestration/plays/solr/java.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "JAVA: Install Open JDK" 3 | apt: 4 | name: openjdk-8-jre-headless 5 | state: present 6 | install_recommends: no 7 | -------------------------------------------------------------------------------- /app/orchestration/plays/solr/solr.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "SOLR: Create solr group" 3 | group: 4 | name: solr 5 | gid: 8983 6 | state: present 7 | 8 | - name: "SOLR: Create solr user" 9 | user: 10 | name: solr 11 | uid: 8983 12 | home: /home/solr 13 | shell: /bin/bash 14 | groups: solr 15 | 16 | - name: "SOLR: Check if core exists" 17 | stat: 18 | path: "{{ solr_configuration_path }}" 19 | register: solr_core_check 20 | changed_when: solr_core_check.stat.exists == false 21 | 22 | - name: "SOLR: Check if archive exists" 23 | stat: 24 | path: "{{ solr_archive_path }}" 25 | register: solr_archive_path_check 26 | changed_when: solr_archive_path_check.stat.exists == false 27 | 28 | - name: "SOLR: Copy archive from mirror" 29 | get_url: 30 | url: "{{ solr_mirror_download_link }}" 31 | dest: "{{ download_dir }}" 32 | validate_certs: no 33 | register: solr_get_url_result 34 | until: "'OK' in solr_get_url_result.msg" 35 | retries: 3 36 | delay: 10 37 | when: solr_archive_path_check.stat.exists == false 38 | 39 | - name: "SOLR: Extract files" 40 | unarchive: 41 | src: "{{ solr_archive_path }}" 42 | dest: /opt 43 | copy: no 44 | when: solr_archive_path_check.stat.exists == false 45 | 46 | - name: "SOLR: Check if directory exists" 47 | stat: 48 | path: "{{ solr_installation_path }}" 49 | register: solr_installation_path_check 50 | changed_when: solr_installation_path_check.stat.exists == false 51 | 52 | - name: "SOLR: Rename unarchived directory" 53 | command: mv {{ solr_temp_unarchived_path }} {{ solr_installation_path }} 54 | when: solr_installation_path_check.stat.exists == false 55 | 56 | - name: "SOLR: Make sure install has correct permissions" 57 | file: 58 | path: "{{ solr_installation_path }}" 59 | state: directory 60 | owner: solr 61 | group: solr 62 | recurse: yes 63 | when: solr_installation_path_check.stat.exists == false 64 | 65 | - name: "SOLR: Check if server is started" 66 | stat: 67 | path: "{{ solr_installation_path }}/bin/solr-8983.pid" 68 | register: solr_pid 69 | changed_when: solr_pid.stat.exists == false 70 | 71 | - name: "SOLR: Start server" 72 | shell: "{{ solr_binary }} start" 73 | become: yes 74 | become_user: solr 75 | when: solr_pid.stat.exists == false 76 | 77 | - name: "SOLR: Create search core" 78 | shell: "{{ solr_binary }} create_core -c {{ solr_core }}" 79 | become: yes 80 | become_user: solr 81 | when: solr_core_check.stat.exists == false 82 | 83 | - name: "SOLR: Check if the schema.xml file exists" 84 | stat: 85 | path: "{{ solr_configuration_path }}/schema.xml" 86 | register: schemaxml_check 87 | changed_when: schemaxml_check.stat.exists == false 88 | 89 | - name: "SOLR: Check if schema.xml file has been configured for Search API Solr" 90 | shell: grep -o "search_api" {{ solr_configuration_path }}/schema.xml | head -n1 || echo "missing" 91 | register: solr_conf_files 92 | when: schemaxml_check.stat.exists == true 93 | changed_when: solr_conf_files.stdout != "search_api" 94 | 95 | - name: "SOLR: Deploy conf files" 96 | copy: 97 | src: "{{ solr_conf }}/" 98 | dest: "{{ solr_configuration_path }}" 99 | mode: 0644 100 | when: schemaxml_check.stat.exists == false or (solr_conf_files is defined and solr_conf_files.stdout != "search_api") 101 | 102 | - name: "SOLR: Ensure correct permissions on conf files" 103 | file: 104 | path: "{{ solr_configuration_path }}" 105 | state: directory 106 | owner: solr 107 | group: users 108 | recurse: yes 109 | when: schemaxml_check.stat.exists == false or (solr_conf_files is defined and solr_conf_files.stdout != "search_api") 110 | 111 | - name: "SOLR: Restart server" 112 | shell: "{{ solr_binary }} restart" 113 | become: yes 114 | become_user: solr 115 | -------------------------------------------------------------------------------- /app/orchestration/plays/stack.yml: -------------------------------------------------------------------------------- 1 | - import_tasks: common/permissions.yml 2 | - import_tasks: common/apache-installation.yml 3 | - import_tasks: common/drucker-config.yml 4 | - import_tasks: php/php.yml 5 | - import_tasks: php/libyaml.yml 6 | - import_tasks: php/pecl-yaml.yml 7 | - import_tasks: tools/composer.yml 8 | - import_tasks: tools/xdebug.yml 9 | - import_tasks: tools/tideways.yml 10 | - import_tasks: tools/phantomjs.yml 11 | - import_tasks: tools/codesniffer.yml 12 | - import_tasks: tools/php-cs-fixer.yml 13 | - import_tasks: tools/coder.yml 14 | # - import_tasks: tools/phpmd.yml 15 | - import_tasks: tools/mcstat.yml 16 | - import_tasks: tools/sass.yml 17 | - import_tasks: db/db-tools.yml 18 | -------------------------------------------------------------------------------- /app/orchestration/plays/system/ssh-keys.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Allows Drush to bootstrap a remote DB. 3 | - name: "SSH: Check if SSH key exists" 4 | stat: 5 | path: "{{ id_rsa }}" 6 | register: rsa_web 7 | ignore_errors: True 8 | 9 | - name: "SSH: Generate SSH key for remote MySQL access" 10 | shell: ssh-keygen -b 4096 -t rsa -f {{ id_rsa }} -q -N "" 11 | args: 12 | creates: "{{ id_rsa }}" 13 | when: rsa_web.stat.exists == false 14 | 15 | - name: "SSH: Make sure permissions are correct on SSH keys" 16 | file: 17 | path: "{{ item }}" 18 | owner: "{{ user }}" 19 | group: "{{ user }}" 20 | with_items: 21 | - "{{ id_rsa }}" 22 | - "{{ id_rsa_pub }}" 23 | when: rsa_web.stat.exists == false 24 | -------------------------------------------------------------------------------- /app/orchestration/plays/system/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "SSH: Enforce hardening" 3 | lineinfile: 4 | dest: "{{ sshd_config }}" 5 | regexp: "{{ item.regexp }}" 6 | line: "{{ item.line }}" 7 | state: present 8 | with_items: 9 | - { 10 | regexp: "^PasswordAuthentication", 11 | line: "PasswordAuthentication no" 12 | } 13 | - { 14 | regexp: "^PermitRootLogin", 15 | line: "PermitRootLogin no" 16 | } 17 | notify: Restart SSH 18 | 19 | - name: "SSH: Check if Docker-specific sudo TTY workaround file exists" 20 | stat: 21 | path: "{{ sudo_tty_workaround_file }}" 22 | register: sudo_tty_workaround 23 | 24 | - name: "SSH: Create Docker-specific sudo TTY workaround file" 25 | file: 26 | path: "{{ sudo_tty_workaround_file }}" 27 | state: touch 28 | mode: 0440 29 | when: sudo_tty_workaround.stat.exists == false 30 | 31 | - name: "SSH: Prevent requiring a password for sudo" 32 | lineinfile: 33 | dest: "{{ sudo_tty_workaround_file }}" 34 | line: "%sudo ALL=(ALL:ALL) NOPASSWD:ALL" 35 | when: sudo_tty_workaround.stat.exists == false 36 | -------------------------------------------------------------------------------- /app/orchestration/plays/system/system-setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Docker is supposed to copy over the local /etc/resolv.conf file. Sometimes it 3 | # fails, so we have to hack our way through modifying it. 4 | - name: "SYSTEM: Copy DNS settings" 5 | command: "cp {{ resolvconf_path }} {{ tmp_resolvconf_path }}" 6 | 7 | - name: "SYSTEM: Update DNS settings" 8 | lineinfile: 9 | dest: "{{ tmp_resolvconf_path }}" 10 | line: "nameserver {{ nameserver }}" 11 | state: present 12 | 13 | - name: "SYSTEM: Replace DNS settings" 14 | command: "cp {{ tmp_resolvconf_path }} {{ resolvconf_path}}" 15 | 16 | - name: "SYSTEM: Clean up system packages" 17 | package: 18 | name: "{{ item }}" 19 | state: absent 20 | purge: yes 21 | with_items: 22 | - vim-tiny 23 | 24 | - name: "SYSTEM: Deploy sources.list template with contrib and non-free repositories" 25 | copy: 26 | src: "{{ sources_list_source_file }}" 27 | dest: "{{ sources_list }}" 28 | mode: 0644 29 | 30 | - name: "SYSTEM: Add Debian codename to sources.list template" 31 | replace: 32 | dest: "{{ sources_list }}" 33 | regexp: '^(.*)CODENAME(.*)$' 34 | replace: '\1{{ codename }}\2' 35 | 36 | - name: "SYSTEM: Refresh APT" 37 | apt: 38 | update_cache: yes 39 | 40 | - name: "SYSTEM: Install system packages" 41 | package: 42 | name: "{{ item }}" 43 | state: present 44 | with_items: 45 | # Useful to run commands as a non-privileged user. 46 | # E.g. /opt/solr/bin/solr start 47 | # See https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user 48 | - acl 49 | # Needed for Ansible's APT module to perform upgrades. 50 | # See https://github.com/ansible/ansible/issues/22673 51 | - aptitude 52 | - ack-grep 53 | # Can be removed in Debian 10. 54 | # See https://packages.debian.org/buster/apt-transport-https 55 | - apt-transport-https 56 | - curl 57 | # Provides dig command. 58 | - dnsutils 59 | - dstat 60 | - exuberant-ctags 61 | - git 62 | - htop 63 | # syslog 64 | - inetutils-syslogd 65 | - iputils-ping 66 | # phantomjs secret dependency 67 | - libfontconfig1 68 | - logrotate 69 | - lsof 70 | - ncdu 71 | - netcat 72 | - net-tools 73 | - ntp 74 | - patchutils 75 | - silversearcher-ag 76 | - strace 77 | - sysstat 78 | - telnet 79 | - tcpdump 80 | - time 81 | - neovim 82 | - wget 83 | # Allows to resize (/usr/bin/resize) the prompt if $COLUMNS and $LINES are 84 | # suddenly messed up, e.g. in a tmux session. 85 | - xterm 86 | 87 | - name: "SYSTEM: Ensure NTP is running" 88 | service: 89 | name: ntp 90 | state: started 91 | enabled: yes 92 | 93 | - name: "SYSTEM: Deploy .bash_aliases" 94 | copy: 95 | src: "{{ bash_aliases_source_file}}" 96 | dest: "{{ home }}" 97 | mode: 0644 98 | owner: "{{ user }}" 99 | group: "{{ user }}" 100 | become: yes 101 | become_user: "{{ user }}" 102 | 103 | - name: "SYSTEM: Add www-data group to drucker account" 104 | user: 105 | name: "{{ user }}" 106 | groups: "{{ apache_user}}" 107 | append: yes 108 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/coder.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "CODER: Check if software is installed" 3 | stat: 4 | path: "{{ coder_binary }}" 5 | register: coder 6 | 7 | - name: "CODER: Install software" 8 | composer: 9 | command: require 10 | arguments: "{{ coder_composer_package }} {{ coder_stable_release }}" 11 | working_dir: "{{ composer_dir_path }}" 12 | become: yes 13 | become_user: "{{ user }}" 14 | when: coder.stat.exists == false 15 | 16 | - name: "CODER: Check if software is up-to-date" 17 | shell: grep -o "{{ coder_stable_release }}" {{ composer_dir_path }}/composer.json || echo "outdated" 18 | register: coder_stable_release_check 19 | changed_when: coder_stable_release_check.stdout != coder_stable_release 20 | 21 | - name: "CODER: Update software" 22 | composer: 23 | command: require 24 | arguments: "{{ coder_composer_package }} {{ coder_stable_release }}" 25 | working_dir: "{{ composer_dir_path }}" 26 | become: yes 27 | become_user: "{{ user }}" 28 | when: coder.stat.exists == true and coder_stable_release_check.stdout != coder_stable_release 29 | 30 | - name: "CODER: Check if bash aliases exist" 31 | shell: grep -o 'MANAGED CODE SNIFFER BLOCK' {{ bashrc }} || echo "absent" 32 | register: coder_aliases 33 | changed_when: coder_aliases == "absent" 34 | 35 | - name: "CODER: Add Code Sniffer aliases" 36 | blockinfile: 37 | dest: "{{ bashrc }}" 38 | block: | 39 | alias drupalcs="phpcs --standard=Drupal --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md'" 40 | alias drupalcsp="phpcs --standard=DrupalPractice --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md'" 41 | alias drupalcbf="phpcbf --standard=Drupal --extensions='php,module,inc,install,test,profile,theme,css,info,txt,md'" 42 | insertafter: EOF 43 | marker: "# {mark} MANAGED CODE SNIFFER BLOCK" 44 | when: coder_aliases.stdout == 'absent' 45 | 46 | - name: "CODER: Register Drupal and DrupalPractice with PHPCS" 47 | command: phpcs --config-set installed_paths {{ codesniffer_binary }} 48 | when: coder.stat.exists == false 49 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/codesniffer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "CODE SNIFFER: Check if phpcs is globally installed" 3 | stat: 4 | path: "{{ phpcs_binary }}" 5 | register: phpcs 6 | 7 | - name: "CODE SNIFFER: Check if phpcbf is globally installed" 8 | stat: 9 | path: "{{ phpcbf_binary }}" 10 | register: phpcbf 11 | 12 | - name: "CODE SNIFFER: Check phpcs version" 13 | shell: phpcs --version | awk '{print $3}' 14 | register: phpcs_version 15 | when: phpcs.stat.exists == true 16 | changed_when: phpcs_version.stdout != phpcs_stable_release 17 | 18 | - name: "CODE SNIFFER: Check phpcbf version" 19 | shell: phpcbf --version | awk '{print $3}' 20 | register: phpcbf_version 21 | when: phpcbf.stat.exists == true 22 | changed_when: phpcbf_version.stdout != phpcbf_stable_release 23 | 24 | - name: "CODE SNIFFER: Copy latest phpcs release from mirror" 25 | get_url: 26 | url: "{{ phpcs_mirror_download_link }}" 27 | dest: "{{ download_dir }}" 28 | mode: 0755 29 | validate_certs: no 30 | register: phpcs_get_url_result 31 | until: "'OK' in phpcs_get_url_result.msg" 32 | retries: 3 33 | delay: 10 34 | when: phpcs.stat.exists == false or phpcs_version.stdout != phpcs_stable_release 35 | 36 | - name: "CODE SNIFFER: Rename phpcs PHAR file" 37 | command: mv {{ phpcs_temp_phar }} {{ phpcs_temp_path }} 38 | when: phpcs.stat.exists == false or phpcs_version.stdout != phpcs_stable_release 39 | 40 | - name: "CODE SNIFFER: Install phpcs globally" 41 | command: mv {{ phpcs_temp_path }} {{ user_programs_path }} 42 | when: phpcs.stat.exists == false or phpcs_version.stdout != phpcs_stable_release 43 | 44 | - name: "CODE SNIFFER: Copy latest phpcbf release from mirror" 45 | get_url: 46 | url: "{{ phpcbf_mirror_download_link }}" 47 | dest: "{{ download_dir }}" 48 | mode: 0755 49 | validate_certs: no 50 | register: phpcbf_get_url_result 51 | until: "'OK' in phpcbf_get_url_result.msg" 52 | retries: 3 53 | delay: 10 54 | when: phpcbf.stat.exists == false or phpcbf_version.stdout != phpcbf_stable_release 55 | 56 | - name: "CODE SNIFFER: Rename phpcbf PHAR file" 57 | command: mv {{ phpcbf_temp_phar }} {{ phpcbf_temp_path }} 58 | when: phpcbf.stat.exists == false or phpcbf_version.stdout != phpcbf_stable_release 59 | 60 | - name: "CODE SNIFFER: Install phpcbf globally" 61 | command: mv {{ phpcbf_temp_path }} {{ user_programs_path }} 62 | when: phpcbf.stat.exists == false or phpcbf_version.stdout != phpcbf_stable_release 63 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/composer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "COMPOSER: Check if software is installed" 3 | stat: 4 | path: "{{ composer_binary }}" 5 | register: composer 6 | 7 | - name: "COMPOSER: Check version" 8 | shell: composer --version | awk '{print $3}' 9 | register: composer_stable_release_check 10 | when: composer.stat.exists == true 11 | changed_when: composer_stable_release_check.stdout != composer_stable_release 12 | 13 | - name: "COMPOSER: Install globally" 14 | get_url: 15 | url: "{{ composer_download_link }}" 16 | dest: "{{ composer_binary }}" 17 | validate_certs: no 18 | force: yes 19 | register: composer_get_url_result 20 | until: "'OK' in composer_get_url_result.msg" 21 | retries: 3 22 | delay: 10 23 | when: composer.stat.exists == false or composer_stable_release_check.stdout != composer_stable_release 24 | 25 | - name: "COMPOSER: Make executable" 26 | file: 27 | path: "{{ composer_binary }}" 28 | mode: 0755 29 | when: composer.stat.exists == false or composer_stable_release_check.stdout != composer_stable_release 30 | 31 | - name: "COMPOSER: Check if software is in PATH" 32 | shell: grep -o "export PATH=\"\$PATH:\$HOME/.composer/vendor/bin\"" {{ bashrc }} || echo "absent" 33 | register: composer_path 34 | changed_when: composer_path.stdout == "absent" 35 | 36 | - name: "COMPOSER: Add software to PATH" 37 | lineinfile: 38 | dest: "{{ bashrc }}" 39 | line: export PATH="$PATH:$HOME/.composer/vendor/bin" 40 | insertafter: EOF 41 | when: composer_path.stdout == 'absent' 42 | 43 | - name: "COMPOSER: Check if .composer directory exists" 44 | stat: 45 | path: "{{ composer_dir_path }}" 46 | register: composer_directory 47 | 48 | - name: "COMPOSER: Create .composer directory" 49 | file: 50 | path: "{{ composer_dir_path }}" 51 | state: directory 52 | owner: "{{ user }}" 53 | group: "{{ user }}" 54 | recurse: yes 55 | when: composer_directory.stat.exists == false 56 | 57 | - name: "COMPOSER: Check if composer.json file exists" 58 | stat: 59 | path: "{{ composer_json_path }}" 60 | register: composer_json 61 | 62 | - name: "COMPOSER: Deploy default composer.json file" 63 | copy: 64 | src: "{{ composer_json_source_file }}" 65 | dest: "{{ composer_dir_path }}" 66 | mode: 0644 67 | become: yes 68 | become_user: "{{ user }}" 69 | when: composer_json.stat.exists == false 70 | 71 | - name: "COMPOSER: Make sure permissions are correct for the .composer directory" 72 | file: 73 | path: "{{ composer_dir_path }}" 74 | owner: "{{ user }}" 75 | group: "{{ user }}" 76 | recurse: yes 77 | 78 | - name: "COMPOSER: Install packages" 79 | composer: 80 | command: install 81 | arguments: --prefer-dist 82 | working_dir: "{{ composer_dir_path }}" 83 | become: yes 84 | become_user: "{{ user }}" 85 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/drupal-console.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Drupal Console Launcher 3 | - name: "DRUPAL CONSOLE: Check if Launcher is installed" 4 | stat: 5 | path: "{{ drupal_console_binary }}" 6 | register: drupal_console_launcher 7 | changed_when: drupal_console_launcher.stat.exists == false 8 | 9 | - name: "DRUPAL CONSOLE: Check Launcher version" 10 | shell: drupal --version | head -n1 | awk '{print $NF}' 11 | register: drupal_console_launcher_check 12 | when: drupal_console_launcher.stat.exists == true 13 | changed_when: drupal_console_launcher_check.stdout != drupal_console_launcher_stable_release 14 | 15 | - name: "DRUPAL CONSOLE: Copy latest Launcher release from mirror" 16 | get_url: 17 | url: "{{ drupal_console_mirror_download_link }}" 18 | dest: "{{ drupal_console_binary }}" 19 | mode: 0755 20 | validate_certs: no 21 | force: yes 22 | register: drupal_console_get_url_result 23 | until: "'OK' in drupal_console_get_url_result.msg" 24 | retries: 3 25 | delay: 10 26 | when: drupal_console_launcher.stat.exists == false or drupal_console_launcher_check.stdout != drupal_console_launcher_stable_release 27 | 28 | - name: "DRUPAL CONSOLE: Update Launcher" 29 | command: drupal self-update 30 | become: yes 31 | when: drupal_console_launcher.stat.exists == true and drupal_console_launcher_check.stdout != drupal_console_launcher_stable_release 32 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/drush.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Drush Launcher 3 | - name: "DRUSH: Check if Launcher is installed" 4 | stat: 5 | path: "{{ drush_launcher }}" 6 | register: drush_launcher 7 | changed_when: drush_launcher.stat.exists == false 8 | 9 | - name: "DRUSH: Check if Launcher needs to be updated" 10 | shell: drush --version| head -n1 | awk '{print $NF}' 11 | register: drush_launcher_stable_release_check 12 | when: drush_launcher.stat.exists == true 13 | changed_when: drush_launcher_stable_release_check.stdout != drush_launcher_stable_release 14 | 15 | - name: "DRUSH: Copy latest Launcher release from mirror" 16 | get_url: 17 | url: "{{ drush_launcher_mirror_download_link }}" 18 | dest: "{{ user_programs_path }}" 19 | mode: 0755 20 | validate_certs: no 21 | register: drush_launcher_get_url_result 22 | until: "'OK' in drush_launcher_get_url_result.msg" 23 | retries: 3 24 | delay: 10 25 | when: drush_launcher.stat.exists == false or drush_launcher_stable_release_check.stdout != drush_launcher_stable_release 26 | 27 | - name: "DRUSH: Rename Launcher PHAR file" 28 | command: mv {{ user_programs_path }}/{{ drush_launcher_archive_file }} {{ user_programs_path }}/drush 29 | when: drush_launcher.stat.exists == false or drush_launcher_stable_release_check.stdout != drush_launcher_stable_release 30 | 31 | # Drush (installed globally) 32 | - name: "DRUSH: Check if the global Drush is installed" 33 | stat: 34 | path: "{{ global_drush }}" 35 | register: global_drush_check 36 | changed_when: global_drush_check.stat.exists == false 37 | 38 | - name: "DRUSH: Copy global-drush to $PATH" 39 | file: 40 | src: "{{ composer_dir_path }}/vendor/drush/drush/drush" 41 | dest: "{{ global_drush }}" 42 | state: link 43 | when: global_drush_check.stat.exists == false 44 | 45 | - name: "DRUSH: Make sure the Launcher falls back to the global Drush" 46 | blockinfile: 47 | dest: "{{ bashrc }}" 48 | block: | 49 | export DRUSH_LAUNCHER_FALLBACK=`which global-drush` 50 | insertafter: EOF 51 | marker: "# {mark} MANAGED DRUSH LAUNCHER FALLBACK BLOCK" 52 | 53 | - name: "DRUSH: Check if Drush's etc directory exists" 54 | stat: 55 | path: "{{ drush_etc_path }}" 56 | register: drush_etc_check 57 | changed_when: drush_etc_check.stat.exists == false 58 | 59 | - name: "DRUSH: Create Drush's etc directory" 60 | file: 61 | path: "{{ drush_etc_path }}" 62 | state: directory 63 | when: drush_etc_check.stat.exists == false 64 | 65 | - name: "DRUSH: Check if sites-aliases directory exists" 66 | stat: 67 | path: "{{ drush_alias_path }}" 68 | register: site_alias_check 69 | changed_when: site_alias_check.stat.exists == false 70 | 71 | - name: "DRUSH: Create site-aliases directory" 72 | file: 73 | path: "{{ drush_alias_path }}" 74 | state: directory 75 | when: site_alias_check.stat.exists == false 76 | 77 | - name: "DRUSH: Create .drush directory" 78 | file: 79 | path: "{{ drush_dir }}" 80 | state: directory 81 | mode: 0755 82 | owner: "{{ user }}" 83 | group: "{{ user }}" 84 | when: site_alias_check.stat.exists == false 85 | 86 | - name: "DRUSH: Check if drush.yml file exists" 87 | stat: 88 | path: "{{ drush_yml_source_file }}" 89 | register: drush_yml_check 90 | changed_when: drush_yml_check.stat.exists == false 91 | 92 | - name: "DRUSH: Deploy drush.yml file" 93 | copy: 94 | src: "{{ drush_yml_source_file }}" 95 | dest: "{{ drush_dir }}" 96 | mode: 0644 97 | when: drush_yml_check.stat.exists == false 98 | ignore_errors: true 99 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/mcstat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MCSTAT: Check if software is installed" 3 | stat: 4 | path: "{{ mcstat_binary }}" 5 | register: mcstat_check 6 | ignore_errors: True 7 | 8 | - name: "MCSTAT: Check if archive exists" 9 | stat: 10 | path: "{{ mcstat_archive_file }}" 11 | register: mcstat_archive 12 | 13 | - name: "MCSTAT: Copy latest release from mirror" 14 | get_url: 15 | url: "{{ mcstat_mirror_download_link }}" 16 | dest: "{{ download_dir }}" 17 | validate_certs: no 18 | register: mcstat_get_url_result 19 | until: "'OK' in mcstat_get_url_result.msg" 20 | retries: 3 21 | delay: 10 22 | when: mcstat_check.stat.exists == false and mcstat_archive.stat.exists == false 23 | 24 | - name: "MCSTAT: Extract files" 25 | unarchive: 26 | src: "{{ mcstat_archive_path }}" 27 | dest: "{{ user_programs_path }}" 28 | copy: no 29 | when: mcstat_check.stat.exists == false and mcstat_archive.stat.exists == false 30 | 31 | - name: "MCSTAT: Create symlink" 32 | file: 33 | src: "{{ mcstat_unarchived_directory }}/mcstat" 34 | dest: "{{ mcstat_binary }}" 35 | state: link 36 | when: mcstat_check.stat.exists == false and mcstat_archive.stat.exists == false 37 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/phantomjs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "GOOGLE CHROME: Download .deb package from the Google repository." 3 | apt: 4 | deb: https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 5 | 6 | - name: "PHANTOMJS: Check if software is installed" 7 | stat: 8 | path: "{{ phantomjs_binary }}" 9 | register: phantomjs 10 | 11 | - name: "PHANTOMJS: Check if software can be updated" 12 | command: phantomjs --version 13 | register: phantomjs_update 14 | when: phantomjs.stat.exists == true 15 | changed_when: phantomjs_update.stdout != phantomjs_stable_version 16 | 17 | - name: "PHANTOMJS: Check if archive exists" 18 | stat: 19 | path: phantomjs-{{ phantomjs_stable_version }}-linux-x86_64.tar.bz2 20 | register: phantomjs_archive 21 | 22 | - name: "PHANTOMJS: Copy latest release from mirror" 23 | get_url: 24 | url: "{{ phantomjs_mirror_download_link }}" 25 | dest: "{{ download_dir }}" 26 | validate_certs: no 27 | register: phantomjs_get_url_result 28 | until: "'OK' in phantomjs_get_url_result.msg" 29 | retries: 3 30 | delay: 10 31 | when: phantomjs.stat.exists == false or phantomjs_update.stdout != phantomjs_stable_version and phantomjs_archive.stat.exists == false 32 | 33 | - name: "PHANTOMJS: Extract files" 34 | unarchive: 35 | src: "{{ phantomjs_archive_path }}" 36 | dest: "{{ download_dir }}" 37 | copy: no 38 | when: phantomjs.stat.exists == false or phantomjs_update.stdout != phantomjs_stable_version 39 | 40 | - name: "PHANTOMJS: Delete outdated executable" 41 | file: 42 | path: "{{ phantomjs_binary }}" 43 | state: absent 44 | when: phantomjs.stat.exists == true and phantomjs_update.stdout != phantomjs_stable_version 45 | 46 | - name: "PHANTOMJS: Install software globally" 47 | command: mv {{ phantomjs_temp_path }}/bin/phantomjs {{ user_programs_path }} 48 | when: phantomjs.stat.exists == false or phantomjs_update.stdout != phantomjs_stable_version 49 | 50 | - name: "PHANTOMJS: Make binary executable" 51 | file: 52 | path: "{{ phantomjs_binary }}" 53 | mode: 0755 54 | when: phantomjs.stat.exists == false or phantomjs_update.stdout != phantomjs_stable_version 55 | 56 | - name: "PHANTOMJS: Delete temporary directory" 57 | file: 58 | path: "{{ item }}" 59 | state: absent 60 | with_items: 61 | - "{{ phantomjs_temp_path }}" 62 | - "{{ phantomjs_archive_path }}" 63 | when: phantomjs.stat.exists == false or phantomjs_update.stdout != phantomjs_stable_version 64 | 65 | # At some point we should think about transitioning over to Chromium's web 66 | # driver. PhantomJS would thus no longer be needed. 67 | - name: "SYSTEM: Install Chromium's web driver" 68 | package: 69 | name: chromium-driver 70 | state: present 71 | force: yes 72 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/php-cs-fixer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHP-CS-FIXER: Check if software is installed" 3 | stat: 4 | path: "{{ php_cs_fixer_binary }}" 5 | register: php_cs_fixer 6 | 7 | - name: "PHP-CS-FIXER: Check version" 8 | shell: php-cs-fixer --version | awk '{print $5}' 9 | register: php_cs_fixer_version 10 | when: php_cs_fixer.stat.exists == true 11 | changed_when: php_cs_fixer_version.stdout != php_cs_fixer_stable_release 12 | 13 | - name: "PHP-CS-FIXER: Copy latest release from mirror" 14 | get_url: 15 | url: "{{ php_cs_fixer_mirror_download_link }}" 16 | dest: "{{ download_dir }}" 17 | mode: 0755 18 | validate_certs: no 19 | register: php_cs_fixer_get_url_result 20 | until: "'OK' in php_cs_fixer_get_url_result.msg" 21 | retries: 3 22 | delay: 10 23 | when: php_cs_fixer.stat.exists == false or php_cs_fixer_version.stdout != php_cs_fixer_stable_release 24 | 25 | - name: "PHP-CS-FIXER: Rename PHAR file" 26 | command: mv {{ php_cs_fixer_temp_phar }} {{ php_cs_fixer_temp_path }} 27 | when: php_cs_fixer.stat.exists == false or php_cs_fixer_version.stdout != php_cs_fixer_stable_release 28 | 29 | - name: "PHP-CS-FIXER: Install globally" 30 | command: mv {{ php_cs_fixer_temp_path }} {{ user_programs_path }} 31 | when: php_cs_fixer.stat.exists == false or php_cs_fixer_version.stdout != php_cs_fixer_stable_release 32 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/phpmd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PHPMD: Check if software is installed" 3 | stat: 4 | path: "{{ phpmd_binary }}" 5 | register: phpmd 6 | 7 | - name: "PHPMD: Check if software needs to be updated" 8 | shell: phpmd --version | awk '{print $NF}' 9 | register: phpmd_stable_release_check 10 | when: phpmd.stat.exists == true 11 | changed_when: phpmd_stable_release_check.stdout != phpmd_stable_version 12 | 13 | - name: "PHPMD: Copy latest release from mirror" 14 | get_url: 15 | url: "{{ phpmd_mirror_download_link }}" 16 | dest: "{{ phpmd_binary }}" 17 | mode: 0755 18 | validate_certs: no 19 | force: yes 20 | register: phpmd_get_url_result 21 | until: "'OK' in phpmd_get_url_result.msg" 22 | retries: 3 23 | delay: 10 24 | when: phpmd.stat.exists == false or phpmd_stable_release_check.stdout != phpmd_stable_version 25 | 26 | - name: "PHPMD: Check if bash alias exists" 27 | shell: grep -o 'MANAGED PHPMD BLOCK' {{ bashrc }} || echo "absent" 28 | register: phpmd_alias 29 | changed_when: phpmd_alias == "absent" 30 | 31 | - name: "PHPMD: Add alias" 32 | blockinfile: 33 | dest: "{{ bashrc }}" 34 | block: | 35 | function phpmd { /usr/local/bin/phpmd "$1" text cleancode,codesize,controversial,design,naming,unusedcode; } 36 | export -f phpmd 37 | insertafter: EOF 38 | marker: "# {mark} MANAGED PHPMD BLOCK" 39 | when: phpmd_alias.stdout == 'absent' 40 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/sass.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "SASS: Install compass" 3 | package: 4 | name: "{{ item }}" 5 | state: present 6 | with_items: 7 | - ruby-compass 8 | - ruby-sass 9 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/tideways.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "TIDEWAYS: Check if the extension is installed" 3 | stat: 4 | path: "{{ tideways_extension_path }}" 5 | register: tideways 6 | 7 | - name: "TIDEWAYS: Check if the extension can be updated" 8 | shell: php -c {{ default_php_ini }} -i | grep 'tideways' | grep -o '{{ tideways_stable_release }}' || echo 'update' 9 | register: tideways_version_check 10 | changed_when: tideways_version_check.stdout == "update" 11 | 12 | - name: "TIDEWAYS: Copy latest release from mirror" 13 | get_url: 14 | url: "{{ tideways_mirror_download_link }}" 15 | dest: "{{ download_dir }}" 16 | validate_certs: no 17 | register: tideways_get_url_result 18 | until: "'OK' in tideways_get_url_result.msg" 19 | retries: 3 20 | delay: 10 21 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 22 | 23 | - name: "TIDEWAYS: Extract files" 24 | unarchive: 25 | src: "{{ tideways_archive }}" 26 | dest: "{{ download_dir }}" 27 | copy: no 28 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 29 | 30 | - name: "TIDEWAYS: Compile extension" 31 | command: "{{ item }} chdir={{ tideways_temp_dir }}" 32 | with_items: 33 | - /usr/bin/phpize 34 | - ./configure 35 | - /usr/bin/make 36 | - /usr/bin/make install 37 | register: compile_tideways 38 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 39 | 40 | - name: "TIDEWAYS: Copy compiled extension" 41 | command: cp {{ tideways_temp_dir }}/modules/{{ tideways_extension_name }} {{ default_php_extensions }} 42 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 43 | 44 | - name: "TIDEWAYS: Make sure permissions are correct" 45 | file: 46 | path: "{{ tideways_extension_path }}" 47 | mode: 0644 48 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 49 | 50 | - name: "TIDEWAYS: Delete temporary directory" 51 | file: 52 | path: "{{ tideways_temp_dir }}" 53 | state: absent 54 | when: tideways.stat.exists == false or tideways_version_check.stdout != tideways_stable_release 55 | 56 | - name: "TIDEWAYS: Check config in php.ini" 57 | shell: grep -o "{{ tideways_extension_name }}" {{ default_php_ini }} || echo "absent" 58 | register: tideways_config 59 | changed_when: tideways_config == "absent" 60 | 61 | - name: "TIDEWAYS: Create output directory" 62 | file: 63 | path: "{{ tideways_output_dir }}" 64 | state: directory 65 | mode: 0777 66 | when: tideways_config.stdout == "absent" 67 | 68 | - name: "TIDEWAYS: Configure extension in php.ini" 69 | blockinfile: 70 | dest: "{{ default_php_ini }}" 71 | block: | 72 | extension={{ tideways_extension_path }} 73 | tideways.output_dir={{ tideways_output_dir }} 74 | marker: ; {mark} MANAGED TIDEWAYS BLOCK 75 | when: tideways_config.stdout == "absent" 76 | 77 | - name: "TIDEWAYS: Ensure Apache is restarted to load the extension" 78 | service: 79 | name: apache2 80 | enabled: yes 81 | state: restarted 82 | 83 | - name: "TIDEWAYS: Ensure PHP-FPM is restarted to load the extension" 84 | service: 85 | name: php{{ default_php_version }}-fpm 86 | enabled: yes 87 | state: restarted 88 | -------------------------------------------------------------------------------- /app/orchestration/plays/tools/xdebug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "XDEBUG: Check if the extension is installed" 3 | stat: 4 | path: "{{ xdebug_extension_path }}" 5 | register: xdebug 6 | 7 | - name: "XDEBUG: Check if the extension can be updated" 8 | shell: ls {{ xdebug_archive_path }} | grep -o {{ xdebug_stable_release }} || echo "absent" 9 | register: xdebug_update 10 | when: xdebug.stat.exists == true 11 | changed_when: xdebug_update.stdout == "absent" 12 | 13 | - name: "XDEBUG: Copy latest release from mirror" 14 | get_url: 15 | url: "{{ xdebug_mirror_download_link }}" 16 | dest: "{{ download_dir }}" 17 | validate_certs: no 18 | register: xdebug_get_url_result 19 | until: "'OK' in xdebug_get_url_result.msg" 20 | retries: 3 21 | delay: 10 22 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 23 | 24 | - name: "XDEBUG: Extract files" 25 | unarchive: 26 | src: "{{ xdebug_archive_path }}" 27 | dest: "{{ download_dir }}" 28 | copy: no 29 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 30 | 31 | - name: "XDEBUG: Compile the extension" 32 | command: "{{ item }} chdir={{ xdebug_unarchived_path }}" 33 | with_items: 34 | - /usr/bin/phpize 35 | - ./configure 36 | - /usr/bin/make 37 | register: compile_xdebug 38 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 39 | 40 | - name: "XDEBUG: Copy compiled extension" 41 | command: cp {{ xdebug_unarchived_path }}/modules/{{ xdebug_extension_name }} {{ default_php_extensions }} 42 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 43 | 44 | - name: "XDEBUG: Make sure permissions are correct" 45 | file: 46 | path: "{{ xdebug_extension_path }}" 47 | mode: 0644 48 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 49 | 50 | - name: "XDEBUG: Delete temporary directory" 51 | file: 52 | path: "{{ xdebug_unarchived_path }}" 53 | state: absent 54 | when: xdebug.stat.exists == false or xdebug_update.stdout != xdebug_stable_release 55 | 56 | - name: "XDEBUG: Check config in php.ini" 57 | shell: grep -o "{{ xdebug_extension_name }}" {{ default_php_ini }} || echo "absent" 58 | register: xdebug_config 59 | changed_when: xdebug_config.stdout == "absent" 60 | 61 | - name: "XDEBUG: Configure extension in php.ini" 62 | blockinfile: 63 | dest: "{{ default_php_ini }}" 64 | block: | 65 | zend_extension = {{ xdebug_extension_path }} 66 | xdebug.remote_host={{ xdebug_remote_host }} 67 | xdebug.remote_port=9000 68 | xdebug.remote_enable=1 69 | xdebug.max_nesting_level=256 70 | marker: ; {mark} MANAGED XDEBUG BLOCK 71 | when: xdebug_config.stdout == "absent" 72 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_base 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/system/ssh.yml 12 | - import_tasks: ../plays/system/system-setup.yml 13 | - import_tasks: ../plays/system/git.yml 14 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/db.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_db 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/common/mirror-deploy.yml 12 | - import_tasks: ../plays/common/apt-update.yml 13 | - import_tasks: ../plays/db/mysql.yml 14 | - import_tasks: ../plays/db/memcached.yml 15 | - import_tasks: ../plays/db/mysql-backup.yml 16 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/edge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_edge 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/common/mirror-deploy.yml 12 | - import_tasks: ../plays/common/apt-update.yml 13 | - import_tasks: ../plays/edge/varnish.yml 14 | - import_tasks: ../plays/edge/nginx.yml 15 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/mirror.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_mirror 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/common/apache-installation.yml 12 | - import_tasks: ../plays/mirror/mirror-vhost.yml 13 | - import_tasks: ../plays/common/apt-repos.yml 14 | - import_tasks: ../plays/common/mirror-downloads.yml 15 | - import_tasks: ../plays/mirror/mirror-setup.yml 16 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/search.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_search 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/common/mirror-deploy.yml 12 | - import_tasks: ../plays/common/apt-update.yml 13 | - import_tasks: ../plays/solr/java.yml 14 | - import_tasks: ../plays/solr/solr.yml 15 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/system/ssh-keys.yml 12 | -------------------------------------------------------------------------------- /app/orchestration/provisioning/web.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: drucker_web 3 | become: yes 4 | 5 | gather_facts: yes 6 | vars_files: 7 | - ../vars.yml 8 | handlers: 9 | - import_tasks: ../handlers.yml 10 | tasks: 11 | - import_tasks: ../plays/common/mirror-deploy.yml 12 | - import_tasks: ../plays/common/apt-update.yml 13 | - import_tasks: ../plays/stack.yml 14 | - import_tasks: ../plays/post-install.yml 15 | -------------------------------------------------------------------------------- /app/requirements.txt: -------------------------------------------------------------------------------- 1 | colorful 2 | docker 3 | -------------------------------------------------------------------------------- /app/services.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Checks if services are correctly running in containers""" 3 | 4 | import subprocess 5 | import colorful 6 | 7 | 8 | def check(container, service, name): 9 | """Starts common services if they're down""" 10 | if not subprocess.getoutput( 11 | "docker exec -it %s pgrep %s | head -1" % (container, service) 12 | ): 13 | print(colorful.red("!!! %s is down." % (name)) + " Starting...") 14 | subprocess.getoutput( 15 | "docker exec -it %s service %s start" % (container, service) 16 | ) 17 | else: 18 | print("- %s is up" % (name)) 19 | 20 | 21 | def phpfpm(drucker): 22 | """Starts PHP-FPM if it's down""" 23 | if not subprocess.getoutput( 24 | "docker exec -it %s pgrep php-fpm%s | head -1" 25 | % (drucker.vars.WEB_CONTAINER, drucker.vars.DEFAULT_PHP) 26 | ): 27 | print(colorful.red("!!! PHP-FPM is down.") + " Starting...") 28 | subprocess.getoutput( 29 | "docker exec -it %s service php%s-fpm start" 30 | % (drucker.vars.WEB_CONTAINER, drucker.vars.DEFAULT_PHP) 31 | ) 32 | else: 33 | print("- PHP-FPM is up") 34 | 35 | 36 | def memcached(container): 37 | """Starts memcached if it's down""" 38 | if not subprocess.getoutput("docker exec -it %s pgrep memcached" % (container)): 39 | print(colorful.red("!!! memcached is down.") + " Starting...") 40 | subprocess.getoutput( 41 | "docker exec -it %s memcached -d -u nobody -m 64 -p 11211 127.0.0.1" 42 | % (container) 43 | ) 44 | else: 45 | print("- memcached is up") 46 | 47 | 48 | def solr(container): 49 | """Starts Apache Solr if it's down""" 50 | if not subprocess.getoutput("docker exec -it %s pgrep java" % (container)): 51 | print(colorful.red("!!! Apache Solr is down.") + " Starting...") 52 | subprocess.getoutput( 53 | "docker exec -it -u solr %s /opt/solr/bin/solr start" % (container) 54 | ) 55 | else: 56 | print("- Apache Solr is up") 57 | -------------------------------------------------------------------------------- /app/variables.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Common variables used across the app""" 3 | 4 | import os 5 | from pathlib import Path 6 | 7 | 8 | APP = "drucker" 9 | APP_VERSION = "dev" 10 | APP_ROOT = os.path.dirname(os.path.dirname(__file__)) 11 | APP_DIR = "%s/app" % (APP_ROOT) 12 | HOME = str(Path.home()) 13 | 14 | EXECUTABLES = ["docker", "ansible"] 15 | EXITCODE_FAIL = 1 16 | EXITCODE_OK = 0 17 | DOMAINS = "drucker.local phpmyadmin.local adminer.local\ 18 | lightning.local blt.local" 19 | HOSTS = "/etc/hosts" 20 | TEST_GROUPS = ["system", "mirror", "edge", "db", "search", "web"] 21 | 22 | # SSH 23 | SSH_CONFIG = "%s/.ssh/config" % (HOME) 24 | 25 | # IP addresses 26 | BASE_IP = "203.0.113.99" 27 | MIRROR_IP = "203.0.113.50" 28 | EDGE_IP = "203.0.113.2" 29 | DB_IP = "203.0.113.12" 30 | WEB_IP = "203.0.113.10" 31 | SEARCH_IP = "203.0.113.13" 32 | 33 | # config file 34 | DEFAULT_CONFIG = APP_ROOT + "/config" 35 | DEFAULT_PUBKEY = "%s/.ssh/id_rsa.pub" % (HOME) 36 | DEFAULT_HTML_PATH = "/var/www/html" 37 | DEFAULT_DB_PATH = "/var/lib/mysql" 38 | KEY_PLACEHOLDER = "key_path" 39 | HTML_PLACEHOLDER = "html_path" 40 | DB_PLACEHOLDER = "db_path" 41 | 42 | # Docker networking 43 | SUBNET = "203.0.113.0/24" 44 | GATEWAY = "203.0.113.254" 45 | CHECK_BRIDGE = "docker network ls | awk '{print $2}' | grep '%s'" % (APP) 46 | CREATE_BRIDGE = """ 47 | docker network create --subnet \"%s\" --gateway \"%s\" \"%s\" 48 | """ % ( 49 | SUBNET, 50 | GATEWAY, 51 | APP, 52 | ) 53 | 54 | # Docker images 55 | DISTRO_IMAGE = "debian:stretch" 56 | INIT_IMAGE = "%s:init" % (APP) 57 | BASE_IMAGE = "%s:base" % (APP) 58 | MIRROR_IMAGE = "%s:mirror" % (APP) 59 | EDGE_IMAGE = "%s:edge" % (APP) 60 | DB_IMAGE = "%s:db" % (APP) 61 | WEB_IMAGE = "%s:web" % (APP) 62 | SEARCH_IMAGE = "%s:search" % (APP) 63 | CHECK_DISTRO_IMAGE = 'docker images | awk \'{print $1":"$2}\' | grep "%s"' % ( 64 | DISTRO_IMAGE 65 | ) 66 | CHECK_INIT_IMAGE = "docker images | awk '{print $1\":\"$2}' | grep %s" % (INIT_IMAGE) 67 | CHECK_BASE_IMAGE = "docker images | awk '{print $1\":\"$2}' | grep %s" % (BASE_IMAGE) 68 | CHECK_SEARCH_IMAGE = 'docker images | awk \'{print $1":"$2}\' | grep "%s"' % ( 69 | SEARCH_IMAGE 70 | ) 71 | UPDATE_DISTRO_IMAGE = """ 72 | docker images | awk '{print $1\":\"$2}' | grep \"%s\" | xargs -L1 docker pull 73 | """ % ( 74 | DISTRO_IMAGE 75 | ) 76 | PULL_DISTRO_IMAGE = "docker pull %s" % (DISTRO_IMAGE) 77 | 78 | # Docker containers 79 | BASE_CONTAINER = "%s_base" % (APP) 80 | MIRROR_CONTAINER = "%s_mirror" % (APP) 81 | EDGE_CONTAINER = "%s_edge" % (APP) 82 | DB_CONTAINER = "%s_db" % (APP) 83 | WEB_CONTAINER = "%s_web" % (APP) 84 | SEARCH_CONTAINER = "%s_search" % (APP) 85 | 86 | CONTAINERS = [ 87 | MIRROR_CONTAINER, 88 | EDGE_CONTAINER, 89 | DB_CONTAINER, 90 | WEB_CONTAINER, 91 | SEARCH_CONTAINER, 92 | ] 93 | 94 | # Hostnames 95 | TLD = "local" 96 | MIRROR_HOSTNAME = "mirror.%s" % (TLD) 97 | EDGE_HOSTNAME = "edge.%s" % (TLD) 98 | WEB_HOSTNAME = "web.%s" % (TLD) 99 | DB_HOSTNAME = "db.%s" % (TLD) 100 | SEARCH_HOSTNAME = "search.%s" % (TLD) 101 | 102 | # Ports 103 | HOST_EDGE_PORT = "81" 104 | MIRROR_PORT = "3142" 105 | EDGE_PORT = "80" 106 | HOST_WEB_PORT = "8180" 107 | HOST_DB_PORT = "3307" 108 | HOST_SEARCH_PORT = "8984" 109 | WEB_PORT = "8080" 110 | DB_PORT = "3306" 111 | SEARCH_PORT = "8983" 112 | HOST_TCP_PORT_MAPPER_WEB = "2047" 113 | TCP_PORT_MAPPER_WEB = "2049" 114 | HOST_TCP_PORT_MAPPER_DB = "2051" 115 | TCP_PORT_MAPPER_DB = "2052" 116 | 117 | # Volume mappings 118 | CONTAINER_DB_PATH = "/var/lib/mysql" 119 | CONTAINER_HTML_PATH = "/var/www/html" 120 | CONTAINER_IMPORT_PATH = "%s/import" % (CONTAINER_HTML_PATH) 121 | HOST_HTML_PATH = CONTAINER_HTML_PATH 122 | 123 | # Services 124 | DEFAULT_PHP = "7.3" 125 | PREVIOUS_PHP = "7.2" 126 | LEGACY_PHP = "7.1" 127 | 128 | # Database 129 | MYSQL_DIR_OWNERSHIP = "mysql" 130 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export SSH_PUBKEY="key_path" 4 | export LOCAL_HTML_PATH="html_path" 5 | export LOCAL_DB_PATH="db_path" 6 | -------------------------------------------------------------------------------- /drucker: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """drucker main dispatcher.""" 4 | import sys 5 | import colorful 6 | import app 7 | 8 | 9 | def dispatch_the_provisioner(drucker): 10 | """drucker initialization, container provisioning and orchestration.""" 11 | app.init.main(drucker) 12 | app.base.main(drucker) 13 | app.mirror.main(drucker) 14 | app.edge.main(drucker) 15 | app.db.main(drucker) 16 | app.search.main(drucker) 17 | app.web.main(drucker) 18 | return drucker.vars.EXITCODE_OK 19 | 20 | 21 | if __name__ == "__main__": 22 | PARSER = app.arguments.get_parser() 23 | 24 | # Name the argparse Namespace object 'DRUCKER'. The 'DRUCKER' object 25 | # travels deep into the codebase since its passed on from here to all 26 | # dispatched code. The drucker object holds more than just CLI-arguments, 27 | # making it the central backbone object of all code: 28 | # 29 | # - DRUCKER.vars: 30 | # The app.variables module, for easy access everywhere. 31 | # 32 | # - DRUCKER.dispatched_function: 33 | # A reference to the function object that got called during 34 | # runtime. It is 'None' when Drucker ran without CLI arguments. 35 | # 36 | # - DRUCKER.app: 37 | # The 'app' argument used for orchestration functions. 38 | # 39 | DRUCKER = PARSER.parse_args() 40 | DRUCKER.vars = app.variables 41 | 42 | # Dispatch and execute Drucker from a central try/except block. We do this 43 | # to catch all exceptions in a single place, more except blocks can be 44 | # added in the future for more granular cases (e.g. 'KeyboardInterrupt'). 45 | # @see https://realpython.com/python-exceptions/ 46 | try: 47 | # Make sure the app can run successfully. 48 | app.requirements.main(DRUCKER) 49 | app.local_setup.main(DRUCKER) 50 | 51 | if DRUCKER.dispatched_function: 52 | EXITCODE = DRUCKER.dispatched_function(DRUCKER) 53 | else: 54 | EXITCODE = dispatch_the_provisioner(DRUCKER) 55 | sys.exit(EXITCODE) 56 | 57 | # RuntimeWarning's are non-fatal and won't stop the program. 58 | except RuntimeWarning as warning: 59 | print(colorful.orange(warning)) 60 | pass 61 | 62 | # RuntimeError's are fatal and stop the program. 63 | except RuntimeError as err: 64 | print(colorful.red(err)) 65 | sys.exit(DRUCKER.vars.EXITCODE_FAIL) 66 | 67 | # Catch all uncaught exceptions and re-raise it. 68 | # 69 | # When this happens its by definition a software bug in Drucker. Because 70 | # of this, we re-raise it using 'raise' so that the backtrace is printed 71 | # and a bug report can be filed. 72 | except Exception as err: 73 | print("\nTHIS UNEXPECTED ERROR OCCURED:\n%s\n\n" % colorful.red(err)) 74 | raise 75 | -------------------------------------------------------------------------------- /drucker-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anavarre/drucker/67fc709be04b113ec4576f0732fa08bd27c211e5/drucker-logo.png -------------------------------------------------------------------------------- /util/drucker-screencast.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Run: 4 | # $ clear ; asciinema rec -t "drucker" -w 2 /tmp/drucker.json 5 | # Then, immediately after: 6 | # $ ./drucker-screencast.sh 7 | # To upload the screencast, type: 8 | # $ asciinema upload /tmp/drucker.json 9 | 10 | function recorder_check() { 11 | RECORDER="$(which asciinema)" 12 | 13 | if [[ ! ${RECORDER} ]]; then 14 | echo 'asciinema must be installed to run this script.' 15 | exit 0 16 | fi 17 | } 18 | 19 | recorder_check 20 | 21 | function wait() { 22 | sleep 2 23 | echo --------------------------------------------- 24 | sleep 3 25 | } 26 | 27 | function separator() { 28 | echo -e "\n" 29 | sleep 2 30 | } 31 | 32 | clear 33 | 34 | echo "*******************************************" 35 | echo "* *" 36 | echo "* This is a quick introduction to drucker *" 37 | echo "* https://github.com/anavarre/drucker *" 38 | echo "* *" 39 | echo "*******************************************" 40 | 41 | sleep 2 42 | 43 | separator 44 | echo "First, let's get confirmation we meet the 45 | minimum software requirements." 46 | 47 | wait 48 | 49 | docker --version |\ 50 | awk '{print $3}' |\ 51 | cut -c -6 |\ 52 | xargs echo Docker version: 53 | 54 | ansible --version |\ 55 | awk '{print $2}' |\ 56 | xargs echo Ansible version: |\ 57 | cut -c -24 ; 58 | 59 | separator 60 | 61 | echo "Now we can check both our Docker images and 62 | corresponding containers are alive and well." 63 | 64 | wait 65 | 66 | docker ps --format 'table {{.Names}}\t{{.Image}}' 67 | 68 | separator 69 | echo "Next up, we want to ensure our hosts file is 70 | correctly configured." 71 | 72 | wait 73 | 74 | tail -n3 /etc/hosts 75 | 76 | separator 77 | echo "To make sure SSH access will be working, we 78 | also need to confirm our config file exists" 79 | 80 | wait 81 | 82 | cat ~/.ssh/config 83 | 84 | separator 85 | echo ">>>> You can find all of the above in the README.md file." 86 | 87 | separator 88 | echo "Okay. Now, let's explore what drucker has to 89 | offer. Type 'drucker help'" 90 | 91 | wait 92 | 93 | "$HOME/Sites/git/github/drucker/drucker" --help 94 | 95 | separator 96 | 97 | echo "Assumptions are being made both with the 'dev' 98 | and 'prod' modes. Just type 'drucker' if you wish 99 | to go with the defaults only." 100 | 101 | wait 102 | separator 103 | 104 | echo "Let's go ahead and run drucker!" 105 | 106 | wait 107 | 108 | "$HOME/Sites/git/github/drucker/drucker" 109 | 110 | separator 111 | echo "That was pretty fast, right? This is because 112 | both the images and containers already exist. 113 | It'll take a good 10-15mn on average broadband 114 | when you run it for the first time." 115 | 116 | separator 117 | sleep 2 118 | echo "OK. Now let's check the headers." 119 | 120 | wait 121 | 122 | http -h drucker.local | egrep '(X-Generator:|Server:|Via:)' 123 | 124 | separator 125 | echo "Excellent. We're running Drupal 8 behind 126 | Varnish and nginx. Non-cacheable requests will be 127 | sent to the Apache backend as with a normal stack." 128 | 129 | separator 130 | echo "This is drucker in a nutshell. Hope you like it. 131 | Thanks for watching!" 132 | -------------------------------------------------------------------------------- /util/var_usage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ANSIBLE_VARS="../orchestration/vars.yml" 4 | PREPARE_FILE=$(awk '{print $1}' ${ANSIBLE_VARS} | grep -Ev '(#|^$)' | sed 's/.$//') 5 | 6 | arr=(${PREPARE_FILE}) 7 | echo ${arr[@]} 8 | --------------------------------------------------------------------------------