[
  {
    "path": ".dockerignore",
    "content": ".DS_Store\n**/.DS_Store\n_env*\n"
  },
  {
    "path": ".gitignore",
    "content": "# credentials\n_env*\nmanta*\n\n# macos frustration\n.DS_Store\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM php:5.6-apache\n\nRUN a2enmod rewrite\n\n# Install the PHP extensions we need, and other packages\nRUN set -ex \\\n    && apt-get update \\\n    && apt-get install -y --no-install-recommends \\\n        curl \\\n        jq \\\n        less \\\n        libjpeg-dev \\\n        libmemcached-dev \\\n        libpng12-dev \\\n        nfs-common \\\n        unzip \\\n    && rm -rf /var/lib/apt/lists/* \\\n    # Memcached 2.2.0 is the latest for PHP < 7\n    # see https://pecl.php.net/package/memcached\n    && pecl install memcached-2.2.0 \\\n    && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \\\n    && docker-php-ext-install gd mysqli opcache \\\n    && docker-php-ext-enable memcached \\\n    # Set recommended PHP.ini settings\n    # See https://secure.php.net/manual/en/opcache.installation.php\n    && { \\\n        echo 'opcache.memory_consumption=128'; \\\n        echo 'opcache.interned_strings_buffer=8'; \\\n        echo 'opcache.max_accelerated_files=4000'; \\\n        echo 'opcache.revalidate_freq=60'; \\\n        echo 'opcache.fast_shutdown=1'; \\\n        echo 'opcache.enable_cli=1'; \\\n    } > /usr/local/etc/php/conf.d/opcache-recommended.ini\n\n# The our helper/glue scripts and configuration for this specific app\nCOPY bin /usr/local/bin\nCOPY etc /etc\n\n# Add Containerpilot and its configuration\n# Releases at https://github.com/joyent/containerpilot/releases\nENV CONTAINERPILOT_VER 2.7.3\nENV CONTAINERPILOT file:///etc/containerpilot.json\n\nRUN set -ex \\\n    && export CONTAINERPILOT_CHECKSUM=2511fdfed9c6826481a9048e8d34158e1d7728bf \\\n    && curl --retry 7 --fail -Lso /tmp/containerpilot.tar.gz \\\n         \"https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz\" \\\n    && echo \"${CONTAINERPILOT_CHECKSUM}  /tmp/containerpilot.tar.gz\" | sha1sum -c \\\n    && tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \\\n    && rm /tmp/containerpilot.tar.gz\n\n# Install Consul\n# Releases at https://releases.hashicorp.com/consul\nRUN set -ex \\\n    && export CONSUL_VERSION=0.7.5 \\\n    && export CONSUL_CHECKSUM=40ce7175535551882ecdff21fdd276cef6eaab96be8a8260e0599fadb6f1f5b8 \\\n    && curl --retry 7 --fail -vo /tmp/consul.zip \"https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip\" \\\n    && echo \"${CONSUL_CHECKSUM}  /tmp/consul.zip\" | sha256sum -c \\\n    && unzip /tmp/consul -d /usr/local/bin \\\n    && rm /tmp/consul.zip \\\n    && mkdir /config\n\n# Install Consul template\n# Releases at https://releases.hashicorp.com/consul-template/\nRUN set -ex \\\n    && export CONSUL_TEMPLATE_VERSION=0.18.3 \\\n    && export CONSUL_TEMPLATE_CHECKSUM=caf6018d7489d97d6cc2a1ac5f1cbd574c6db4cd61ed04b22b8db7b4bde64542 \\\n    && curl --retry 7 --fail -Lso /tmp/consul-template.zip \"https://releases.hashicorp.com/consul-template/${CONSUL_TEMPLATE_VERSION}/consul-template_${CONSUL_TEMPLATE_VERSION}_linux_amd64.zip\" \\\n    && echo \"${CONSUL_TEMPLATE_CHECKSUM}  /tmp/consul-template.zip\" | sha256sum -c \\\n    && unzip /tmp/consul-template.zip -d /usr/local/bin \\\n    && rm /tmp/consul-template.zip\n\n# Install wp-cli, http://wp-cli.org\nENV WP_CLI_CONFIG_PATH /var/www/html/wp-cli.yml\nRUN set -ex \\\n    && curl --retry 7 --fail -Ls -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \\\n    && chmod +x wp-cli.phar \\\n    && mv wp-cli.phar /usr/local/bin/wp \\\n    && wp --info --allow-root\n\n# Copy the WordPress skeleton from this repo into the container\n# This includes any themes and/or plugins we've added to the content/themes and content/plugins directories.\nCOPY /var/www/html /var/www/html\nRUN chown -R www-data:www-data /var/www/html/*\n\n# Install WordPress via wp-cli & move the default themes to our content dir\n# Releases at https://core.svn.wordpress.org/tags/ and https://wordpress.org/news/category/releases/\nENV WORDPRESS_VERSION 4.7.5\nRUN set -ex \\\n    && wp --allow-root core download --version=${WORDPRESS_VERSION} \\\n    && mv /var/www/html/wordpress/wp-content/themes/* /var/www/html/content/themes/\n\n# Install HyperDB, https://wordpress.org/plugins/hyperdb\n# Releases at https://wordpress.org/plugins/hyperdb/developers/ , though no SHA1 fingerprints are published\nRUN set -ex \\\n    && export HYPERDB_VERSION=1.1 \\\n    && curl --retry 7 --fail -Ls -o /var/www/html/hyperdb.zip https://downloads.wordpress.org/plugin/hyperdb.${HYPERDB_VERSION}.zip \\\n    && unzip hyperdb.zip \\\n    && chown -R www-data:www-data /var/www/html/hyperdb \\\n    && mv hyperdb/db.php /var/www/html/content/. \\\n    && rm -rf /var/www/html/hyperdb.zip /var/www/html/hyperdb \\\n    && touch /var/www/html/content/db-config.php\n\n# Install ztollman's object-cache.php or object caching to memcached\nRUN set -ex \\\n    && curl --retry 7 --fail -Ls -o /var/www/html/content/object-cache.php https://raw.githubusercontent.com/tollmanz/wordpress-pecl-memcached-object-cache/master/object-cache.php\n\n# The volume is defined after we install everything\nVOLUME /var/www/html\n\nCMD [\"/usr/local/bin/containerpilot\", \\\n    \"apache2-foreground\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>\n 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Lesser General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n                            NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    {description}\n    Copyright (C) {year}  {fullname}\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License along\n    with this program; if not, write to the Free Software Foundation, Inc.,\n    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  {signature of Ty Coon}, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.\n\n"
  },
  {
    "path": "Makefile",
    "content": "# Makefile for shipping and testing the container image.\n\nMAKEFLAGS += --warn-undefined-variables\n.DEFAULT_GOAL := build\n.PHONY: *\n\n# we get these from CI environment if available, otherwise from git\nGIT_COMMIT ?= $(shell git rev-parse --short HEAD)\nGIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)\nWORKSPACE ?= $(shell pwd)\n\nnamespace ?= autopilotpattern\ntag := branch-$(shell basename $(GIT_BRANCH))\nimageWordpress := $(namespace)/wordpress\nimageNginx := $(namespace)/wordpress-nginx\n\n#dockerLocal := DOCKER_HOST= DOCKER_TLS_VERIFY= DOCKER_CERT_PATH= docker\ndockerLocal := docker\n#composeLocal := DOCKER_HOST= DOCKER_TLS_VERIFY= DOCKER_CERT_PATH= docker-compose\ncomposeLocal := docker-compose\n\n## Display this help message\nhelp:\n\t@awk '/^##.*$$/,/[a-zA-Z_-]+:/' $(MAKEFILE_LIST) | awk '!(NR%2){print $$0p}{p=$$0}' | awk 'BEGIN {FS = \":.*?## \"}; {printf \"\\033[36m%-20s\\033[0m %s\\n\", $$1, $$2}' | sort\n\n\n# ------------------------------------------------\n# Container builds\n\n## Builds the application container image locally\nbuild:\n\t$(dockerLocal) build -t=$(imageWordpress):$(tag) .\n\tcd nginx && $(dockerLocal) build -t=$(imageNginx):$(tag) .\n\n## Push the current application container images to the Docker Hub\npush:\n\t$(dockerLocal) push $(imageWordpress):$(tag)\n\t$(dockerLocal) push $(imageNginx):$(tag)\n\n## Tag the current images as 'latest'\ntag:\n\t$(dockerLocal) tag $(imageWordpress):$(tag) $(imageWordpress):latest\n\t$(dockerLocal) tag $(imageNginx):$(tag) $(imageNginx):latest\n\n## Push latest tag(s) to the Docker Hub\nship: tag\n\t$(dockerLocal) push $(imageWordpress):$(tag)\n\t$(dockerLocal) push $(imageWordpress):latest\n\t$(dockerLocal) push $(imageNginx):$(tag)\n\t$(dockerLocal) push $(imageNginx):latest\n\n\n# ------------------------------------------------\n# Test running\n\n## Pull the container images from the Docker Hub\npull:\n\t$(dockerLocal) pull $(imageWordpress):$(tag)\n\t$(dockerLocal) pull $(imageNginx):$(tag)\n\n## Print environment for build debugging\ndebug:\n\t@echo WORKSPACE=$(WORKSPACE)\n\t@echo GIT_COMMIT=$(GIT_COMMIT)\n\t@echo GIT_BRANCH=$(GIT_BRANCH)\n\t@echo namespace=$(namespace)\n\t@echo tag=$(tag)\n\t@echo imageWordpress=$(imageWordpress)\n\t@echo imageNginx=$(imageNginx)\n\n# -------------------------------------------------------\n# helper functions for testing if variables are defined\n#\ncheck_var = $(foreach 1,$1,$(__check_var))\n__check_var = $(if $(value $1),,\\\n\t$(error Missing $1 $(if $(value 2),$(strip $2))))\n"
  },
  {
    "path": "README.md",
    "content": "# Autopilot Pattern WordPress\n\n*A robust and highly-scalable implementation of WordPress in Docker using the Autopilot Pattern*\n\n[![DockerPulls](https://img.shields.io/docker/pulls/autopilotpattern/wordpress.svg)](https://registry.hub.docker.com/u/autopilotpattern/wordpress/)\n[![DockerStars](https://img.shields.io/docker/stars/autopilotpattern/wordpress.svg)](https://registry.hub.docker.com/u/autopilotpattern/wordpress/)\n\n---\n\n### Containerized and easily scalable\n\nThis project uses the Autopilot Pattern to automate operations, including discovery and configuration, for easy scaling to any size. All component containers use [ContainerPilot](https://www.joyent.com/containerpilot) and [Consul](https://consul.io/) to configure themselves. This also allows each service to be scaled independently to handle incoming traffic and as more services are added, the containers that consume these services will reconfigure themselves accordingly.\n\n### Project architecture\n\nA running cluster includes the following components:\n\n- [ContainerPilot](https://www.joyent.com/containerpilot): included in our MySQL containers to orchestrate bootstrap behavior and coordinate replication using keys and checks stored in Consul in the `preStart`, `health`, and `onChange` handlers.\n- [MySQL](https://github.com/autopilotpattern/mysql/): we're using the [Autopilot Pattern implementation of MySQL](https://www.joyent.com/blog/dbaas-simplicity-no-lock-in) for automatic backups and self-clustering so that we can deploy and scale easily\n- [HyperDB](https://wordpress.org/plugins/hyperdb/): an \"advanced database class that replaces a few of the WordPress built-in database functions\" to support the MySQL cluster that's necessary for scaling WordPress; everything is automatically configured so running a scalable WordPress site is no more complex than running without the scaling features\n- [Memcached](https://github.com/autpilotpattern/memcached/): improves performance by keeping frequently accessed data in memory so WordPress doesn't have to query the database for every request; the images include [tollmanz's Memcached plugin](https://github.com/tollmanz/wordpress-pecl-memcached-object-cache) pre-installed, and ContainerPilot automatically configures it as we scale\n- [Nginx](https://github.com/autopilotpattern/nginx): the front-end load balancer for the WordPress environment; passes traffic from users to the WordPress containers on the back-end\n- [NFS](https://github.com/autopilotpattern/nfsserver/): stores user uploaded files so these files can be shared between many WordPress containers\n- [Consul](https://www.consul.io/): used to coordinate replication and failover\n- [Manta](https://www.joyent.com/object-storage): the Joyent object store, for securely and durably storing our MySQL snapshots\n- [Prometheus](https://github.com/autopilotpattern/prometheus): an optional, [open source monitoring tool](https://prometheus.io) that tracks the performance of each component and demonstrates [ContainerPilot telemetry](https://www.joyent.com/blog/containerpilot-telemetry)\n- [WP-CLI](http://wp-cli.org/): to make managing WordPress easier\n\n### How do I use this thing?\n\nPick the answer that fits:\n\n1. For the hello world experience: follow the directions below for configuration, then `docker-compose up -d` and you're done.\n1. For building your own WordPress in Docker: clone this repository and place the WordPress theme you want to use into the `var/www/html/content/themes` directory. Develop locally using the `local-compose.yml` file, then build your Docker image and run those in the cloud with your own `docker-compose.yml` file that specifies your custom image.\n\nThe instructions below will get you set up to run containers on [Triton](https://www.joyent.com/), or anywhere that supports the Autopilot Pattern.\n\n### Getting started on Triton\n\n1. [Get a Joyent account](https://my.joyent.com/landing/signup/) and [add your SSH key](https://docs.joyent.com/public-cloud/getting-started).\n1. Install the [Docker Toolbox](http://docker.com/toolbox) (including `docker` and `docker-compose`) on your laptop or other environment, as well as the [Joyent Triton CLI](https://www.joyent.com/blog/introducing-the-triton-command-line-tool)\n1. [Configure Docker and Docker Compose for use with Joyent](https://docs.joyent.com/public-cloud/api-access/docker):\n\n```bash\ncurl -O https://raw.githubusercontent.com/joyent/sdc-docker/master/tools/sdc-docker-setup.sh && chmod +x sdc-docker-setup.sh\n./sdc-docker-setup.sh -k us-east-1.api.joyent.com <ACCOUNT> ~/.ssh/<PRIVATE_KEY_FILE>\n```\n\n### Configure your environment\n\nCheck that everything is configured correctly by running `./setup.sh`. You'll need an SSH key that has access to Manta, the object store where the MySQL backups are stored. Pass the path of that SSH key as `./setup.sh ~/path/to/MANTA_SSH_KEY`. The script will create an `_env` file that names the variables that you will need to run your WordPress environment.\n\n#### Manta settings\n\nThe script will set defaults for almost every config variable, but the Manta config is required and must be set manually. The two most important variables there are:\n\n```\nMANTA_BUCKET=/<username>/stor/<bucketname>  # an existing Manta bucket\nMANTA_USER=<username> # a user with access to that bucket\n```\n\nThe MySQL container will take a backup during its `preStart` handler and periodically while running. Configure these Manta settings to specify how and where this backup is stored. Here you need to specify the `MANTA_USER`, and also the `MANTA_BUCKET` where the backups will be stored.\n\n#### WordPress configuration\n\nThe setup script will set working defaults for the entire WordPress configuration. The defaults will work for a quick \"hello world\" experience, but you'll probably want to set your own values for many fields.\n\n```\n# Environment variables for for WordPress site\nWORDPRESS_URL=http://my-site.example.org/\nWORDPRESS_SITE_TITLE=My Blog\nWORDPRESS_ADMIN_EMAIL=user@example.net\nWORDPRESS_ADMIN_USER=admin\nWORDPRESS_ADMIN_PASSWORD=<random string>\nWORDPRESS_ACTIVE_THEME=twentysixteen\nWORDPRESS_CACHE_KEY_SALT=<random string>\n#WORDPRESS_TEST_DATA=true # uncomment to import a collection of test content on start\n```\n\nThis block is the typical information you must provide when installing WordPress. The URL of the site, the site title and admin user information are all straightforward. `WORDPRESS_ACTIVE_THEME` is the theme that will be activated automatically when the container starts. This will typically be theme that you are developing in this repo, or one of the default themes. `WORDPRESS_CACHE_KEY_SALT` should be set to a unique string, the object caching in WordPress will use this salt to determine the cache keys for information it sets on the Memcached container.\n\nIf you are not bringing your own theme in this repo, you can choose from these default themes for the `WORDPRESS_ACTIVE_THEME` variable:\n\n- `twentyfifteen`\n- `twentyfourteen`\n- `twentysixteen`\n\nThe script will set a `WORDPRESS_URL` value for Triton users using [Container Name Service](https://www.joyent.com/blog/introducing-triton-container-name-service) that will make it easy to test the containers without setting any DNS information. You can [`CNAME` your site DNS](https://www.joyent.com/blog/introducing-triton-container-name-service#example-global-dns) to that to make it easy to scale and replace the Nginx containers at the front of your site without ever needing to update the DNS configuration.\n\nSetting `WORDPRESS_TEST_DATA` will download the [manovotny/wptest](https://github.com/manovotny/wptest) content library when the WordPress container starts.\n\n#### MySQL settings\n\nThe setup script will set default values for the MySQL configuration, including randomly generated passwords.\n\n```\n# Environment variables for MySQL service\n# WordPress database/WPDB information\nMYSQL_USER=wpdbuser\nMYSQL_PASSWORD=<random string>\nMYSQL_DATABASE=wp\n# MySQL replication user, should be different from above\nMYSQL_REPL_USER=repluser\nMYSQL_REPL_PASSWORD=<random string>\n```\n\nThese values will be automatically set in the `wp-config.php`. The last two options are used by the Autopilot Pattern MySQL container to set up its replication when scaled up to more than a single container. You can keep `repluser`, but set a unique password for your environment.\n\n#### WordPress unique salts\n\nAs with most of the other configuration blocks, the setup script will set reasonable defaults for these values.\n\n```\n# Wordpress security salts\n# These must be unique for your install to ensure the security of the site\nWORDPRESS_AUTH_KEY=<random string>\nWORDPRESS_SECURE_AUTH_KEY=<random string>\nWORDPRESS_LOGGED_IN_KEY=<random string>\nWORDPRESS_NONCE_KEY=<random string>\nWORDPRESS_AUTH_SALT=<random string>\nWORDPRESS_SECURE_AUTH_SALT=<random string>\nWORDPRESS_LOGGED_IN_SALT=<random string>\nWORDPRESS_NONCE_SALT=<random string>\n```\n\nThese variables are how WordPress secures your logins and other secret info. These should be unique for your site. You can set your own values, or use [this WordPress tool](https://api.wordpress.org/secret-key/1.1/salt/) to generate a new set of random values.\n\n#### Consul\n\nFinally we need to configure an environment variable with the location of our Consul service. The setup script will pre-set this for Triton users.\n\n```\nCONSUL=<IP or DNS to Consul>\n```\n\nFor local development, we use Docker links and simply set this to `CONSUL=consul`, but on Triton we use [Container Name Service](https://www.joyent.com/blog/introducing-triton-container-name-service) so that we can have a raft of Consul instances operating as a highly available service ([see example](https://www.joyent.com/blog/introducing-triton-container-name-service#example-consul-bootstrapping)).\n\n### A note on Nginx\n\nThis project also builds it's own Nginx container that is based on the [AutoPilot Pattern Nginx](https://github.com/autopilotpattern/nginx). We build a custom Nginx container to more easily inject our custom configurations. The configs located in the `/nginx` directory should work well for most use cases of this project, but they can be customized and baked into the Nginx image if the need arises.\n\n### Start the containers!\n\nAfter configuring everything, we are now ready to start the containers. To do that simply execute `docker-compose up -d` to spin everything up on Triton. Open your browser to the `WORDPRESS_URL` and enjoy your new site!\n\nFor local development, use `docker-compose -f local-compose.yml up -d`.\n\n### Going big\n\nTo scale, use `docker-compose scale...`. For example, the following will set the scale of the WordPress, Memcached, Nginx, and MySQL services to three instances each:\n\n```bash\ndocker-compose scale wordpress=3 memcached=3 nginx=3 mysql=3\n```\n\nIf there are few instances running for any of those services, more will be added to meet the specified count. As you scale, the application will automatically reconfigure itself so that everything is connected. All the Nginx instances will connect to all the WordPress instances, and those will connect to all the Memcached and MySQL instances. If an instance should unexpectedly crash, the other instances will automatically reconfigure to re-route requests around the failed instance.\n\nTo scale back down, simply run `docker-compose scale...` and specify a smaller number of instances.\n\n### Compatibility\n\nThis project has been fully tested and documented to run in Docker in local development environments and on [Joyent Triton](https://www.joyent.com), however it has been demonstrated on, or is believe compatible with container environments including:\n\n- [Mantl](http://mantl.io)\n- [DC/OS](https://dcos.io)\n- [Docker Swarm](https://www.docker.com/products/docker-swarm)\n- [Kubernetes](http://kubernetes.io)\n- Others\n\n### Contributing\n\n- Please [report bugs in Github](https://github.com/autopilotpattern/wordpress/issues) (and check the bug list for known bugs)\n- It's open source, [pull requests welcome](https://github.com/autopilotpattern/wordpress/pulls)!\n\n### Sponsors\n\nInitial development of this project was sponsored by [Joyent](https://www.joyent.com) and [10up](http://10up.com).\n"
  },
  {
    "path": "bin/health.sh",
    "content": "#!/bin/bash\n\n/usr/local/bin/wp --allow-root core is-installed \\\n\t&& /usr/local/bin/wp --allow-root option get siteurl \\\n\t&& /usr/bin/curl --fail -s -o /dev/null http://localhost/\n"
  },
  {
    "path": "bin/onchange-db.sh",
    "content": "#!/bin/bash\n\n/usr/local/bin/onchange-wp-config.sh\n\nconsul-template \\\n    -once \\\n    -dedup \\\n    -consul-addr ${CONSUL}:8500 \\\n    -template \"/var/www/html/db-config.php.ctmpl:/var/www/html/content/db-config.php\"\n"
  },
  {
    "path": "bin/onchange-memcached.sh",
    "content": "#!/bin/bash\n\nconsul-template \\\n    -once \\\n    -dedup \\\n    -consul-addr ${CONSUL}:8500 \\\n    -template \"/var/www/html/memcached-config.php.ctmpl:/var/www/html/memcached-config.php\"\n"
  },
  {
    "path": "bin/onchange-nfs.sh",
    "content": "#!/bin/bash\n\nif [[ `curl -s ${CONSUL}:8500/v1/health/state/passing | grep nfs`  ]]\nthen\n  echo \"nfs is healthy, mounting uploads directory....\"\n  NFS=$(curl -s http://${CONSUL}:8500/v1/catalog/service/nfs?passing | jq -r '.[0] | .ServiceAddress')\n  mount -t nfs -v -o nolock,vers=3 ${NFS}:/exports /var/www/html/content/uploads\n  echo \"removing no-uploads.php mu-plugin\"\n  rm /var/www/html/content/mu-plugins/no-uploads.php\n  # check 'wp core is-installed' here to prevent errors in the log on first run\n  # before WP gets installed into the database\n  if $(wp --allow-root core is-installed)\n  then\n    echo \"adding 'upload_files' capability back to default roles\"\n    # only these roles have 'upload_files' cap by default\n    for role in administrator editor author\n    do\n      if [ \"$role\" != 'role' ]\n      then\n        wp --allow-root cap add ${role} upload_files\n      fi\n    done\n  fi\nelse\n  echo \"nfs is not healthly, umounting uploads directory...\"\n  umount -f -l /var/www/html/content/uploads\n  echo \"creating mu-plugin for NFS error in wp-admin\"\n  cp /var/www/html/inactive-plugins/no-uploads.php /var/www/html/content/mu-plugins/\n\n  echo \"removing 'upload_files' capability from all roles...\"\n  for role in $(wp --allow-root role list --fields=role --format=csv)\n  do\n    if [ \"$role\" != 'role' ]\n    then\n      wp --allow-root cap remove ${role} upload_files\n    fi\n  done\nfi\n"
  },
  {
    "path": "bin/onchange-wp-config.sh",
    "content": "#!/bin/bash\n# The WordPress config file\nconsul-template \\\n    -once \\\n    -dedup \\\n    -consul-addr ${CONSUL}:8500 \\\n    -template \"/var/www/html/wp-config.php.ctmpl:/var/www/html/wp-config.php\"\n"
  },
  {
    "path": "bin/prestart.sh",
    "content": "#!/bin/bash\n\n# Refresh all config files in order\n#\n# This script is typically called once at the container start, but\n# it can be called manually if WP config details must be changed\n\n# The database and memcached config files are separate to avoid collisions\n# if their backends' onChange handlers are triggered simultaneously\necho \"******running preStart script*********\"\n\nuntil [[ `curl -s ${CONSUL}:8500/v1/health/state/passing | grep mysql-primary`  ]]\ndo\n  echo \"mysql-primary not healthly....\"\n  sleep 5\ndone\n\nuntil [[ `curl -s ${CONSUL}:8500/v1/health/state/passing | grep nfs`  ]]\ndo\n  echo \"no healthly nfs server avaliable yet....\"\n  sleep 5\ndone\n\necho \"mysql-primary and nfs are now healthly, moving on...\"\n\n/usr/local/bin/onchange-db.sh\n/usr/local/bin/onchange-memcached.sh\n/usr/local/bin/onchange-nfs.sh\n\n# The WordPress config file\n/usr/local/bin/onchange-wp-config.sh\n\nif $(wp --allow-root core is-installed)\nthen\n  echo \"WP is installed\"\n  # run update-db to ensure the database schema is up to date in case the WP version was upgraded in the Docker image\n  wp --allow-root core update-db\nelse\n  echo \"WP is NOT installed\"\n  echo \"installing now....\"\n  # TODO: check WORDPRESS_URL to ensure it has http:// or https:// at the beginning, if not put it in\n  wp --allow-root core install --url=$WORDPRESS_URL --title=\"$WORDPRESS_SITE_TITLE\" --admin_user=$WORDPRESS_ADMIN_USER --admin_password=$WORDPRESS_ADMIN_PASSWORD --admin_email=$WORDPRESS_ADMIN_EMAIL --skip-email\n  # update siteurl to work with our directory structure\n  # wp option update for siteurl REQUIRES http://, need to determine will we handle that here\n  # or ask for it in the _env file or test for it above\n  wp --allow-root option update siteurl `wp --allow-root option get siteurl`/wordpress\n  # set a nice default permalink structure\n  wp --allow-root option update permalink_structure '/%year%/%monthnum%/%postname%/'\n  # set theme\n  if [ -n \"$WORDPRESS_ACTIVE_THEME\" ]\n  then\n    wp --allow-root theme activate $WORDPRESS_ACTIVE_THEME\n  fi\n\n  if [ -n \"$WORDPRESS_TEST_DATA\" ]\n  then\n    echo \"installing WP test content\"\n    wp --allow-root plugin install wordpress-importer --activate\n    curl -OL https://raw.githubusercontent.com/manovotny/wptest/master/wptest.xml\n    wp --allow-root import wptest.xml --authors=create\n    wp --allow-root plugin uninstall wordpress-importer --deactivate\n    chown -R www-data:www-data /var/www/html/content/uploads/*\n    rm wptest.xml\n  fi\nfi\n"
  },
  {
    "path": "bin/sensor.sh",
    "content": "#!/bin/bash\nset -e\n\nhelp() {\n    echo 'Uses cli tools free and top to determine current CPU and memory usage'\n    echo 'for the telemetry service.'\n}\n\n# memory usage in percent\nmemory() {\n    # awk oneliner to get memory usage\n    # free -m | awk 'NR==2{printf \"Memory Usage: %s/%sMB (%.2f%%)\\n\", $3,$2,$3*100/$2 }'\n    # output:\n    # Memory Usage: 15804/15959MB (99.03%)\n    (>&2 echo \"memory check fired\")\n    local memory=$(free -m | awk 'NR==2{printf \"%.2f\", $3*100/$2 }')\n    echo ${memory}\n}\n\n# cpu load\ncpu() {\n    # oneliner to display cpu load\n    # top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\\n\", $(NF-2)}'\n    (>&2 echo \"cpu check fired\")\n    local cpuload=$(top -bn1 | grep load | awk '{printf \"%.2f\", $(NF-2)}')\n    echo ${cpuload}\n}\n\ncmd=$1\nif [ ! -z \"$cmd\" ]; then\n    shift 1\n    $cmd \"$@\"\n    exit\nfi\n\nhelp\n"
  },
  {
    "path": "docker-compose.yml",
    "content": "# An demo version of WordPress for easy scaling\nwordpress:\n  image: autopilotpattern/wordpress:latest\n  restart: always\n  env_file: _env\n  environment:\n    - CONSUL_AGENT=1\n  ports:\n    - 80\n    - 9090\n  labels:\n    # Setting the CNS service name\n    - triton.cns.services=wp-wordpress\n    # Soft anti-affinity to avoid other WordPress instances\n    - com.docker.swarm.affinities=[\"container!=~*wordpress*\"]\n    # Set the package\n    - com.joyent.package=g4-highcpu-1G\n\n# Consul is the service catalog that helps discovery between the components\n# Change \"-bootstrap\" to \"-bootstrap-expect 3\", then scale to 3 or more to\n# turn this into an HA Consul raft.\nconsul:\n  image: autopilotpattern/consul:latest\n  command: >\n    /usr/local/bin/containerpilot\n    /bin/consul agent -server\n    -bootstrap\n    -config-dir=/etc/consul\n    -ui-dir /ui\n  restart: always\n  env_file: _env\n  ports:\n    - 8500\n  dns:\n    - 127.0.0.1\n  labels:\n    - triton.cns.services=wp-consul\n    # Soft anti-affinity to avoid all other containers\n    - com.docker.swarm.affinities=[\"container!=~*\"]\n    - com.joyent.package=g4-highcpu-128M\n\n# NFS is used to store user uploads\nnfs:\n  image: autopilotpattern/nfsserver:latest\n  restart: always\n  env_file: _env\n  environment:\n    - CONSUL_AGENT=1\n  expose:\n    - 111\n    - 1892\n    - 2049\n  labels:\n    - triton.cns.services=wp-nfs\n    - com.docker.swarm.affinities=[\"container!=~*\"]\n    - com.joyent.package=g4-highcpu-256M\n\n# The MySQL database will automatically cluster and scale\n# see https://www.joyent.com/blog/dbaas-simplicity-no-lock-in\nmysql:\n  image: autopilotpattern/mysql:latest\n  restart: always\n  env_file: _env\n  environment:\n    - CONSUL_AGENT=1\n  expose:\n    - 3306\n  labels:\n    - triton.cns.services=wp-mysql\n    - com.docker.swarm.affinities=[\"container!=~*mysql*\"]\n    - com.joyent.package=g4-highcpu-4G\n\n# Memcached is a high performance object cache\nmemcached:\n  image: autopilotpattern/memcached:latest\n  restart: always\n  env_file: _env\n  environment:\n    - CONSUL_AGENT=1\n  ports:\n    - 11211\n  labels:\n    - triton.cns.services=wp-memcached\n    - com.docker.swarm.affinities=[\"container!=~*memcached*\"]\n    - com.joyent.package=g4-highcpu-512M\n\n# Nginx as a load-balancing tier and reverse proxy\nnginx:\n  image: autopilotpattern/wordpress-nginx:latest\n  restart: always\n  ports:\n    - 80\n    - 443\n    - 9090\n  env_file: _env\n  environment:\n    - CONSUL_AGENT=1\n  labels:\n    - triton.cns.services=wp-nginx,nginx\n    - com.docker.swarm.affinities=[\"container!=~*nginx*\"]\n    - com.joyent.package=g4-highcpu-512M\n\n# Prometheus is an open source performance monitoring tool\n# it is included here for demo purposes and is not required\nprometheus:\n  image: autopilotpattern/prometheus:branch-triton-support\n  restart: always\n  env_file: _env\n  ports:\n    - 9090\n  labels:\n    - triton.cns.services=wp-prometheus\n    - com.docker.swarm.affinities=[\"container!=~*prometheus*\"]\n    - com.joyent.package=g4-highcpu-1G\n"
  },
  {
    "path": "etc/containerpilot.json",
    "content": "{\n  \"consul\": \"{{ if .CONSUL_AGENT }}localhost{{ else }}{{ .CONSUL }}{{ end }}:8500\",\n  \"preStart\": \"/usr/local/bin/prestart.sh\",\n  \"services\": [\n    {\n      \"name\": \"wordpress\",\n      \"port\": 80,\n      \"health\": \"/usr/local/bin/health.sh\",\n      \"poll\": 10,\n      \"ttl\": 25\n    }\n  ],\n  \"backends\": [\n    {\n      \"name\": \"mysql\",\n      \"poll\": 7,\n      \"onChange\": \"/usr/local/bin/onchange-db.sh\"\n    },\n    {\n      \"name\": \"mysql-primary\",\n      \"poll\": 7,\n      \"onChange\": \"/usr/local/bin/onchange-db.sh\"\n    },\n    {\n      \"name\": \"nfs\",\n      \"poll\": 11,\n      \"onChange\": \"/usr/local/bin/onchange-nfs.sh\"\n    },\n    {\n      \"name\": \"memcached\",\n      \"poll\": 5,\n      \"onChange\": \"/usr/local/bin/onchange-memcached.sh\"\n    }\n  ],\n  \"coprocesses\": [{{ if .CONSUL_AGENT }}\n    {\n      \"command\": [\"/usr/local/bin/consul\", \"agent\",\n                  \"-data-dir=/data\",\n                  \"-config-dir=/config\",\n                  \"-rejoin\",\n                  \"-retry-join\", \"{{ .CONSUL }}\",\n                  \"-retry-max\", \"10\",\n                  \"-retry-interval\", \"10s\"],\n      \"restarts\": \"unlimited\"\n    }{{ end }}],\n  \"telemetry\": {\n    \"port\": 9090,\n    \"sensors\": [\n      {\n        \"name\": \"wp_memory_percent\",\n        \"help\": \"percentage of memory used\",\n        \"type\": \"gauge\",\n        \"poll\": 5,\n        \"check\": [\"/usr/local/bin/sensor.sh\", \"memory\"]\n      },\n      {\n        \"name\": \"wp_cpu_load\",\n        \"help\": \"cpu load\",\n        \"type\": \"gauge\",\n        \"poll\": 5,\n        \"check\": [\"/usr/local/bin/sensor.sh\", \"cpu\"]\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "local-compose.yml",
    "content": "# See docker-compose.yml for further descriptions and configuration details of each service\n\nwordpress:\n  extends:\n    file: docker-compose.yml\n    service: wordpress\n  build: .\n  privileged: true\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n  ports:\n    - \"80\"\n\nconsul:\n  extends:\n    file: docker-compose.yml\n    service: consul\n  restart: \"no\"\n  ports:\n    - 8500:8500\n\nnfs:\n  extends:\n    file: docker-compose.yml\n    service: nfs\n  privileged: true\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n  ports:\n    - 111\n    - 1892:1892\n    - 2049\n\nmysql:\n  extends:\n    file: docker-compose.yml\n    service: mysql\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n  ports:\n    - 3306\n\nmemcached:\n  extends:\n    file: docker-compose.yml\n    service: memcached\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n\nnginx:\n  extends:\n    file: docker-compose.yml\n    service: nginx\n  build: nginx/\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n  ports:\n    - 80:80\n\nprometheus:\n  extends:\n    file: docker-compose.yml\n    service: prometheus\n  restart: \"no\"\n  environment:\n    - CONSUL=consul\n  links:\n    - consul:consul\n  ports:\n    - 9090:9090\n"
  },
  {
    "path": "nginx/.dockerignore",
    "content": ".DS_Store\n**/.DS_Store\n_env*\n"
  },
  {
    "path": "nginx/Dockerfile",
    "content": "# a minimal Nginx container including containerbuddy and a simple virtulhost config\nFROM autopilotpattern/nginx:1.13-r7.0.1\n\n# Add our configuration files\nCOPY etc /etc\n"
  },
  {
    "path": "nginx/etc/containerpilot.json",
    "content": "{\n  \"consul\": \"{{ if .CONSUL_AGENT }}localhost{{ else }}{{ .CONSUL }}{{ end }}:8500\",\n  \"preStart\": \"generate-config\",\n  \"logging\": {\"level\": \"DEBUG\"},\n  \"services\": [\n    {\n      \"name\": \"nginx\",\n      \"port\": 80,\n      \"health\": \"/usr/bin/curl --fail --silent --show-error --output /dev/null http://localhost/nginx-health\",\n      \"poll\": 10,\n      \"ttl\": 25,\n      \"interfaces\": [\"eth0\"]\n    },\n    {\n      \"name\": \"nginx-public\",\n      \"port\": 80,\n      \"health\": \"/usr/bin/curl --fail --silent --show-error --output /dev/null http://localhost/nginx-health\",\n      \"poll\": 10,\n      \"ttl\": 25,\n      \"interfaces\": [\"eth1\", \"eth0\"]\n    }{{ if .ACME_DOMAIN }},\n    {\n      \"name\": \"nginx-public-ssl\",\n      \"port\": 443,\n      \"health\": \"/usr/local/bin/acme init && /usr/bin/curl --insecure --fail --silent --show-error --output /dev/null --header \\\"HOST: {{ .ACME_DOMAIN }}\\\" https://localhost/nginx-health\",\n      \"poll\": 10,\n      \"ttl\": 25,\n      \"interfaces\": [\"eth1\", \"eth0\"]\n    }{{ end }}\n  ],\n  \"backends\": [\n    {\n      \"name\": \"wordpress\",\n      \"poll\": 7,\n      \"onChange\": \"reload\"\n    }\n  ],\n  \"coprocesses\": [{{ if .CONSUL_AGENT }}\n    {\n      \"command\": [\"/usr/local/bin/consul\", \"agent\",\n                  \"-data-dir=/data\",\n                  \"-config-dir=/config\",\n                  \"-rejoin\",\n                  \"-retry-join\", \"{{ .CONSUL }}\",\n                  \"-retry-max\", \"10\",\n                  \"-retry-interval\", \"10s\"],\n      \"restarts\": \"unlimited\"\n    }{{ end }}\n    {{ if and .CONSUL_AGENT .ACME_DOMAIN }},{{ end }}\n    {{ if .ACME_DOMAIN }}\n    {\n      \"command\": [\"/usr/local/bin/consul-template\",\n                  \"-config\", \"/etc/acme/watch.hcl\",\n                  \"-consul\", \"{{ if .CONSUL_AGENT }}localhost{{ else }}{{ .CONSUL }}{{ end }}:8500\"],\n      \"restarts\": \"unlimited\"\n    }{{ end }}],\n  \"telemetry\": {\n    \"port\": 9090,\n    \"sensors\": [\n      {\n        \"name\": \"nginx_connections_unhandled_total\",\n        \"help\": \"Number of accepted connnections that were not handled\",\n        \"type\": \"gauge\",\n        \"poll\": 5,\n        \"check\": [\"sensor\", \"unhandled\"]\n      },\n      {\n        \"name\": \"nginx_connections_load\",\n        \"help\": \"Ratio of active connections (less waiting) to the maximum worker connections\",\n        \"type\": \"gauge\",\n        \"poll\": 5,\n        \"check\": [\"sensor\", \"connections_load\"]\n      }\n    ]\n  },\n  \"tasks\": [{{ if .ACME_DOMAIN }}\n    {\n      \"name\": \"acme-checkin\",\n      \"command\": [ \"/usr/local/bin/acme\", \"checkin\" ],\n      \"frequency\": \"5m\",\n      \"timeout\": \"10s\"\n    },\n    {\n      \"name\": \"acme-renew-certs\",\n      \"command\": [ \"/usr/local/bin/acme\", \"renew-certs\" ],\n      \"frequency\": \"12h\",\n      \"timeout\": \"10m\"\n    },\n    {\n      \"name\": \"clean-unused-certs\",\n      \"command\": [\"/usr/local/bin/acme\", \"clean-certs\" ],\n      \"frequency\": \"24h\",\n      \"timeout\": \"10m\"\n    }{{ end }}\n  ]\n}\n"
  },
  {
    "path": "nginx/etc/nginx/templates/conf.d/site.conf",
    "content": "{{ $acme_domain := env \"ACME_DOMAIN\" }}\n{{ $ssl_ready := env \"SSL_READY\" }}\n\n# If we're listening on https, define an http listener that redirects everything to https\n{{ if eq $ssl_ready \"true\" }}\nserver { \n    server_name _;\n    listen      80;\n\n    include /etc/nginx/health.conf;\n    \n    location / {\n        return 301 https://$host$request_uri;\n    }\n}\n{{ end }}\n\n# The main server block\nserver {\n    server_name _;\n    # Listen on port 80 unless we have certificates installed, then listen on 443\n    listen {{ if ne $ssl_ready \"true\" }}80{{ else }}443 ssl{{ end }};\n\n    include /etc/nginx/health.conf;\n\n    location /.well-known/acme-challenge {\n        alias /var/www/acme/challenge;\n    }\n\n    {{ if service \"wordpress\" }}\n    rewrite ^/wp-admin/?(.*) /wordpress/wp-admin/$1;\n\n    location ^~ / {\n        proxy_pass http://wordpress;\n        proxy_redirect off;\n        proxy_set_header Host $http_host;\n        proxy_set_header X-Forwarded-Proto $scheme;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    }{{ else }}\n    # return 503 errors if we don't have our expected back-end\n    location / {\n        return 503;\n    }{{ end }}\n}\n"
  },
  {
    "path": "nginx/etc/nginx/templates/nginx.conf",
    "content": "# This is an example Nginx configuration template file.\n# Adjust the values below as required for your application.\n\nuser  nginx;\nworker_processes  1;\n\nerror_log  /var/log/nginx/error.log warn;\npid        /var/run/nginx.pid;\n\nevents {\n    worker_connections  1024;\n}\n\nhttp {\n    include       /etc/nginx/mime.types;\n    default_type  application/octet-stream;\n\n    map $status $isNot2xx {\n        ~^2 0;\n        default 1;\n    }\n    \n    log_format  main  '$remote_addr - $remote_user [$time_local] \"$request\" '\n                      '$status $body_bytes_sent \"$http_referer\" '\n                      '\"$http_user_agent\" \"$http_x_forwarded_for\" '\n                      '$upstream_addr';\n\n    access_log  /var/log/nginx/access.log  main;\n\n    sendfile           on;\n    keepalive_timeout  65;\n\n    {{ $ssl_ready := env \"SSL_READY\" }}\n\n    {{ if eq $ssl_ready \"true\" }}\n    include ssl.conf;\n    {{ end }}\n\n    {{ if service \"wordpress\" }}\n    upstream wordpress {\n        # write the address:port pairs for each healthy wordpress node\n        {{range service \"wordpress\"}}\n        server {{.Address}}:{{.Port}};\n        {{end}}\n    }{{ end }}\n\n    include conf.d/*.conf;\n}\n"
  },
  {
    "path": "setup.sh",
    "content": "#!/bin/bash\nset -e -o pipefail\n\nhelp() {\n    echo\n    echo 'Usage ./setup.sh ~/path/to/MANTA_PRIVATE_KEY'\n    echo\n    echo 'Checks that your Triton and Docker environment is sane and configures'\n    echo 'an environment file to use.'\n    echo\n    echo 'MANTA_PRIVATE_KEY is the filesystem path to an SSH private key'\n    echo 'used to connect to Manta for the database backups.'\n    echo\n    echo 'Additional details must be configured in the _env file, but this script will properly'\n    echo 'encode the SSH key details for use with this this project.'\n    echo\n    echo '-'\n    echo\n    echo 'Usage ./setup.sh get-cns-hostname'\n    echo\n    echo 'Output the CNS hostname suitable for aliasing in DNS for custom domain names.'\n    echo\n}\n\n\n# populated by `check` function whenever we're using Triton\nTRITON_USER=\nTRITON_DC=\nTRITON_ACCOUNT=\n\n# ---------------------------------------------------\n# Top-level commands\n\n# Output aliasable CNS hostname\nget-cns-hostname() {\n    TRITON_DC=$(triton profile get | awk -F\"/\" '/url:/{print $3}' | awk -F'.' '{print $1}')\n    TRITON_ACCOUNT=$(triton account get | awk -F\": \" '/id:/{print $2}')\n    echo \"nginx.svc.${TRITON_ACCOUNT}.${TRITON_DC}.cns.joyent.com\"\n}\n\n# Check for correct configuration and setup _env file\nenvcheck() {\n\n    if [ -z \"$1\" ]; then\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Please provide a path to a SSH private key to access Manta.'\n        tput sgr0 # clear\n\n        help\n        exit 1\n    fi\n\n    if [ ! -f \"$1\" ]; then\n        tput rev  # reverse\n        tput bold # bold\n        echo 'SSH private key for Manta is unreadable.'\n        tput sgr0 # clear\n\n        help\n        exit 1\n    fi\n\n    # Assign args to named vars\n    MANTA_PRIVATE_KEY_PATH=$1\n\n    command -v docker >/dev/null 2>&1 || {\n        echo\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Docker is required, but does not appear to be installed.'\n        tput sgr0 # clear\n        echo 'See https://docs.joyent.com/public-cloud/api-access/docker'\n        exit 1\n    }\n    command -v json >/dev/null 2>&1 || {\n        echo\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Error! JSON CLI tool is required, but does not appear to be installed.'\n        tput sgr0 # clear\n        echo 'See https://apidocs.joyent.com/cloudapi/#getting-started'\n        exit 1\n    }\n\n    command -v triton >/dev/null 2>&1 || {\n        echo\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Error! Joyent Triton CLI is required, but does not appear to be installed.'\n        tput sgr0 # clear\n        echo 'See https://www.joyent.com/blog/introducing-the-triton-command-line-tool'\n        exit 1\n    }\n\n    # make sure Docker client is pointed to the same place as the Triton client\n    local docker_user=$(docker info 2>&1 | awk -F\": \" '/SDCAccount:/{print $2}')\n    local docker_dc=$(echo $DOCKER_HOST | awk -F\"/\" '{print $3}' | awk -F'.' '{print $1}')\n    TRITON_USER=$(triton profile get | awk -F\": \" '/account:/{print $2}')\n    TRITON_DC=$(triton profile get | awk -F\"/\" '/url:/{print $3}' | awk -F'.' '{print $1}')\n    TRITON_ACCOUNT=$(triton account get | awk -F\": \" '/id:/{print $2}')\n    if [ ! \"$docker_user\" = \"$TRITON_USER\" ] || [ ! \"$docker_dc\" = \"$TRITON_DC\" ]; then\n        echo\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Error! The Triton CLI configuration does not match the Docker CLI configuration.'\n        tput sgr0 # clear\n        echo\n        echo \"Docker user: ${docker_user}\"\n        echo \"Triton user: ${TRITON_USER}\"\n        echo \"Docker data center: ${docker_dc}\"\n        echo \"Triton data center: ${TRITON_DC}\"\n        exit 1\n    fi\n\n    local triton_cns_enabled=$(triton account get | awk -F\": \" '/cns/{print $2}')\n    if [ ! \"true\" == \"$triton_cns_enabled\" ]; then\n        echo\n        tput rev  # reverse\n        tput bold # bold\n        echo 'Error! Triton CNS is required and not enabled.'\n        tput sgr0 # clear\n        echo\n        echo 'Consider running:'\n        echo '  triton account update triton_cns_enabled=true'\n        echo\n        exit 1\n    fi\n\n    # setup environment file\n    if [ ! -f \"_env\" ]; then\n        echo '# Environment variables for for WordPress site' > _env\n        echo '# please include the scheme http:// or https:// in the URL variable' >> _env\n\n        echo 'WORDPRESS_URL=http://'nginx.svc.${TRITON_ACCOUNT}.${TRITON_DC}.triton.zone >> _env\n        echo 'WORDPRESS_SITE_TITLE=Autopilot Pattern WordPress test site' >> _env\n        echo 'WORDPRESS_ADMIN_EMAIL=user@example.net' >> _env\n        echo 'WORDPRESS_ADMIN_USER=admin-'$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 3) >> _env\n        echo 'WORDPRESS_ADMIN_PASSWORD='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 11) >> _env\n        echo 'WORDPRESS_ACTIVE_THEME=twentysixteen' >> _env\n        echo 'WORDPRESS_CACHE_KEY_SALT='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo '#WORDPRESS_TEST_DATA=true # uncomment to import a collection of test content on start' >> _env\n        echo >> _env\n\n        echo '# Wordpress security salts' >> _env\n        echo '# These must be unique for your install to ensure the security of the site' >> _env\n        echo 'WORDPRESS_AUTH_KEY='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_SECURE_AUTH_KEY='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_LOGGED_IN_KEY='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_NONCE_KEY='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_AUTH_SALT='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_SECURE_AUTH_SALT='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_LOGGED_IN_SALT='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo 'WORDPRESS_NONCE_SALT='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 53) >> _env\n        echo >> _env\n\n        echo '# Nginx LetsEncrypt (ACME) config' >> _env\n        echo '# be sure ACME_DOMAIN host and WORDPRESS_URL host are the same, if using automated SSL via LetsEncrypt' >> _env\n        echo '# ACME_ENV defaults to \"staging\", uncomment following ACME_ENV line to switch to LetsEncrypt production endpoint' >> _env\n        echo '#ACME_DOMAIN='nginx.svc.${TRITON_ACCOUNT}.${TRITON_DC}.triton.zone >> _env\n        echo '#ACME_ENV=production' >> _env\n        echo >> _env\n\n        echo '# Environment variables for MySQL service' >> _env\n        echo '# WordPress database/WPDB information' >> _env\n        echo 'MYSQL_USER=wpdbuser' >> _env\n        echo 'MYSQL_PASSWORD='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 7) >> _env\n        echo 'MYSQL_DATABASE=wp' >> _env\n        echo '# MySQL replication user, should be different from above' >> _env\n        echo 'MYSQL_REPL_USER=repluser' >> _env\n        echo 'MYSQL_REPL_PASSWORD='$(cat /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 7) >> _env\n        echo >> _env\n\n        echo '# Environment variables for backups to Manta' >> _env\n        echo 'MANTA_URL=https://us-east.manta.joyent.com' >> _env\n        echo 'MANTA_BUCKET=/<username>/stor/<bucketname> # an existing Manta bucket' >> _env\n        echo 'MANTA_USER=<username> # a user with access to that bucket' >> _env\n        echo 'MANTA_SUBUSER=' >> _env\n        echo 'MANTA_ROLE=' >> _env\n\n        # MANTA_KEY_ID must be the md5 formatted key fingerprint. A SHA256 will result in errors.\n        set +o pipefail\n        # The -E option was added to ssh-keygen recently; if it doesn't work, then\n        # assume we're using an older version of ssh-keygen that only outputs MD5 fingerprints\n        ssh-keygen -yl -E md5 -f ${MANTA_PRIVATE_KEY_PATH} > /dev/null 2>&1\n        if [ $? -eq 0 ]; then\n            echo MANTA_KEY_ID=$(ssh-keygen -yl -E md5 -f ${MANTA_PRIVATE_KEY_PATH} | awk '{print substr($2,5)}') >> _env\n        else\n            echo MANTA_KEY_ID=$(ssh-keygen -yl -f ${MANTA_PRIVATE_KEY_PATH} | awk '{print $2}') >> _env\n        fi\n        set -o pipefail\n\n        # munge the private key so that we can pass it into an env var sanely\n        # and then unmunge it in our startup script\n        echo MANTA_PRIVATE_KEY=$(cat ${MANTA_PRIVATE_KEY_PATH} | tr '\\n' '#') >> _env\n        echo >> _env\n\n        echo '# Consul discovery via Triton CNS' >> _env\n        echo CONSUL=wp-consul.svc.${TRITON_ACCOUNT}.${TRITON_DC}.cns.joyent.com >> _env\n        echo >> _env\n\n        echo 'Edit the _env file to confirm and set your desired configuration details'\n    else\n        echo 'Existing _env file found, exiting'\n        exit\n    fi\n}\n\n# ---------------------------------------------------\n# parse arguments\n\n# Get function list\nfuncs=($(declare -F -p | cut -d \" \" -f 3))\n\nuntil\n    if [ ! -z \"$1\" ]; then\n        # check if the first arg is a function in this file, or use a default\n        if [[ \" ${funcs[@]} \" =~ \" $1 \" ]]; then\n            cmd=$1\n            shift 1\n        else\n            cmd=\"envcheck\"\n        fi\n\n        $cmd \"$@\"\n        if [ $? == 127 ]; then\n            help\n        fi\n\n        exit\n    else\n        help\n    fi\ndo\n    echo\ndone\n"
  },
  {
    "path": "var/www/html/.htaccess",
    "content": "<IfModule mod_rewrite.c>\nRewriteEngine On\nRewriteBase /\nRewriteRule ^index\\.php$ - [L]\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteRule . /index.php [L]\n</IfModule>\n"
  },
  {
    "path": "var/www/html/content/mu-plugins/index.php",
    "content": ""
  },
  {
    "path": "var/www/html/content/mu-plugins/register-theme-directory.php",
    "content": "<?php\n\nregister_theme_directory( ABSPATH . 'wp-content/themes/' );"
  },
  {
    "path": "var/www/html/content/plugins/index.php",
    "content": ""
  },
  {
    "path": "var/www/html/content/themes/index.php",
    "content": ""
  },
  {
    "path": "var/www/html/content/uploads/.empty",
    "content": ""
  },
  {
    "path": "var/www/html/db-config.php.ctmpl",
    "content": "<?php\n/**\n * HyperDB configuration file\n *\n * This file is automatically generated via a template\n * parsed by consul-template, https://github.com/hashicorp/consul-template .\n *\n * Last update {{timestamp}}\n *\n * This file should be installed at ABSPATH/db-config.php\n *\n * $wpdb is an instance of the hyperdb class which extends the wpdb class.\n *\n * See readme.txt for documentation.\n */\n\n/** DB hosts **/\n\n/**\n * See usage details below in the section on \"Configuration Functions\"\n */\n\n/**\n * The DB master\n *\n * This has reads turned off, though any reads following a write _will_ be against the master.\n */\n{{if service \"mysql-primary\"}}\n{{with index (service \"mysql-primary\") 0}}\n$wpdb->add_database(array(\n\t'host'     => '{{.Address}}:{{.Port}}',\n\t'user'     => DB_USER,\n\t'password' => DB_PASSWORD,\n\t'name'     => DB_NAME,\n\t'write'    => 1,\n\t'read'     => 0,\n\t'dataset'  => 'global',\n));{{end}}\n{{end}}\n\n{{if service \"mysql\"}}\n/**\n * The DB replicas\n *\n * These are read-only.\n */\n{{range service \"mysql\"}}\n$wpdb->add_database(array(\n\t'host'     => '{{.Address}}:{{.Port}}',\n\t'user'     => DB_USER,\n\t'password' => DB_PASSWORD,\n\t'name'     => DB_NAME,\n\t'write'    => 0,\n\t'read'     => 1,\n\t'dataset'  => 'global',\n\t'timeout'  => 0.2,\n));{{end}}\n{{else}}\n/**\n * No DB replicas are healthy, so we're adding the master in as a read-host.\n */\n{{range service \"mysql-primary\"}}\n$wpdb->add_database(array(\n\t'host'     => '{{.Address}}:{{.Port}}',\n\t'user'     => DB_USER,\n\t'password' => DB_PASSWORD,\n\t'name'     => DB_NAME,\n\t'write'    => 0,\n\t'read'     => 1,\n\t'dataset'  => 'global',\n));{{end}}\n{{end}}\n\n/** HyperDB configuration documentation and examples **/\n\n/**\n * Introduction to HyperDB configuration\n *\n * HyperDB can manage connections to a large number of databases. Queries are\n * distributed to appropriate servers by mapping table names to datasets.\n *\n * A dataset is defined as a group of tables that are located in the same\n * database. There may be similarly-named databases containing different\n * tables on different servers. There may also be many replicas of a database\n * on different servers. The term \"dataset\" removes any ambiguity. Consider a\n * dataset as a group of tables that can be mirrored on many servers.\n *\n * Configuring HyperDB involves defining databases and datasets. Defining a\n * database involves specifying the server connection details, the dataset it\n * contains, and its capabilities and priorities for reading and writing.\n * Defining a dataset involves specifying its exact table names or registering\n * one or more callback functions that translate table names to datasets.\n */\n\n/** Variable settings **/\n\n/**\n * save_queries (bool)\n * This is useful for debugging. Queries are saved in $wpdb->queries. It is not\n * a constant because you might want to use it momentarily.\n * Default: false\n */\n$wpdb->save_queries = false;\n\n/**\n * persistent (bool)\n * This determines whether to use mysql_connect or mysql_pconnect. The effects\n * of this setting may vary and should be carefully tested.\n * Default: false\n */\n$wpdb->persistent = false;\n\n/**\n * max_connections (int)\n * This is the number of mysql connections to keep open. Increase if you expect\n * to reuse a lot of connections to different servers. This is ignored if you\n * enable persistent connections.\n * Default: 10\n */\n$wpdb->max_connections = 10;\n\n/**\n * check_tcp_responsiveness\n * Enables checking TCP responsiveness by fsockopen prior to mysql_connect or\n * mysql_pconnect. This was added because PHP's mysql functions do not provide\n * a variable timeout setting. Disabling it may improve average performance by\n * a very tiny margin but lose protection against connections failing slowly.\n * Default: true\n */\n$wpdb->check_tcp_responsiveness = true;\n\n\n\n/** Configuration Functions **/\n\n/**\n * $wpdb->add_database( $database );\n *\n * $database is an associative array with these parameters:\n * host          (required) Hostname with optional :port. Default port is 3306.\n * user          (required) MySQL user name.\n * password      (required) MySQL user password.\n * name          (required) MySQL database name.\n * read          (optional) Whether server is readable. Default is 1 (readable).\n *\t\t\t\t\t\t   Also used to assign preference. See \"Network topology\".\n * write         (optional) Whether server is writable. Default is 1 (writable).\n *                          Also used to assign preference in multi-master mode.\n * dataset       (optional) Name of dataset. Default is 'global'.\n * timeout       (optional) Seconds to wait for TCP responsiveness. Default is 0.2\n * lag_threshold (optional) The minimum lag on a slave in seconds before we consider it lagged.\n *\t\t\t\t\t\t\tSet null to disable. When not set, the value of $wpdb->default_lag_threshold is used.\n */\n\n/**\n * $wpdb->add_table( $dataset, $table );\n *\n * $dataset and $table are strings.\n */\n\n/**\n * $wpdb->add_callback( $callback, $callback_group = 'dataset' );\n *\n * $callback is a callable function or method. $callback_group is the\n * group of callbacks, this $callback belongs to.\n *\n * Callbacks are executed in the order in which they are registered until one\n * of them returns something other than null.\n *\n * The default $callback_group is 'dataset'. Callback in this group\n * will be called with two arguments and expected to compute a dataset or return null.\n * $dataset = $callback($table, &$wpdb);\n *\n * Anything evaluating to false will cause the query to be aborted.\n *\n * For more complex setups, the callback may be used to overwrite properties of\n * $wpdb or variables within hyperdb::connect_db(). If a callback returns an\n * array, HyperDB will extract the array. It should be an associative array and\n * it should include a $dataset value corresponding to a database added with\n * $wpdb->add_database(). It may also include $server, which will be extracted\n * to overwrite the parameters of each randomly selected database server prior\n * to connection. This allows you to dynamically vary parameters such as the\n * host, user, password, database name, lag_threshold and TCP check timeout.\n */\n\n/** Masters and slaves\n *\n * A database definition can include 'read' and 'write' parameters. These\n * operate as boolean switches but they are typically specified as integers.\n * They allow or disallow use of the database for reading or writing.\n *\n * A master database might be configured to allow reading and writing:\n *   'write' => 1,\n *   'read'  => 1,\n * while a slave would be allowed only to read:\n *   'write' => 0,\n *   'read'  => 1,\n *\n * It might be advantageous to disallow reading from the master, such as when\n * there are many slaves available and the master is very busy with writes.\n *   'write' => 1,\n *   'read'  => 0,\n * HyperDB tracks the tables that it has written since instantiation and sending\n * subsequent read queries to the same server that received the write query.\n * Thus a master set up this way will still receive read queries, but only\n * subsequent to writes.\n */\n\n\n/**\n * Network topology / Datacenter awareness\n *\n * When your databases are located in separate physical locations there is\n * typically an advantage to connecting to a nearby server instead of a more\n * distant one. The read and write parameters can be used to place servers into\n * logical groups of more or less preferred connections. Lower numbers indicate\n * greater preference.\n *\n * This configuration instructs HyperDB to try reading from one of the local\n * slaves at random. If that slave is unreachable or refuses the connection,\n * the other slave will be tried, followed by the master, and finally the\n * remote slaves in random order.\n * Local slave 1:   'write' => 0, 'read' => 1,\n * Local slave 2:   'write' => 0, 'read' => 1,\n * Local master:    'write' => 1, 'read' => 2,\n * Remote slave 1:  'write' => 0, 'read' => 3,\n * Remote slave 2:  'write' => 0, 'read' => 3,\n *\n * In the other datacenter, the master would be remote. We would take that into\n * account while deciding where to send reads. Writes would always be sent to\n * the master, regardless of proximity.\n * Local slave 1:   'write' => 0, 'read' => 1,\n * Local slave 2:   'write' => 0, 'read' => 1,\n * Remote slave 1:  'write' => 0, 'read' => 2,\n * Remote slave 2:  'write' => 0, 'read' => 2,\n * Remote master:   'write' => 1, 'read' => 3,\n *\n * There are many ways to achieve different configurations in different\n * locations. You can deploy different config files. You can write code to\n * discover the web server's location, such as by inspecting $_SERVER or\n * php_uname(), and compute the read/write parameters accordingly. An example\n * appears later in this file using the legacy function add_db_server().\n */\n\n/**\n * Slaves lag awareness\n *\n * HyperDB accommodates slave lag by making decisions, based on the defined lag\n * threshold. If the lag threshold is not set, it will ignore the slave lag.\n * Otherwise, it will try to find a non-lagged slave, before connecting to a lagged one.\n *\n * A slave is considered lagged, if it's replication lag is bigger than the lag threshold\n * you have defined in $wpdb->$default_lag_threshold or in the per-database settings, using\n * add_database(). You can also rewrite the lag threshold, by returning\n * $server['lag_threshold'] variable with the 'dataset' group callbacks.\n *\n * HyperDB does not check the lag on the slaves. You have to define two callbacks\n * callbacks to do that:\n *\n * $wpdb->add_callback( $callback, 'get_lag_cache' );\n *\n * and\n *\n * $wpdb->add_callback( $callback, 'get_lag' );\n *\n * The first one is called, before connecting to a slave and should return\n * the replication lag in seconds or false, if unknown, based on $wpdb->lag_cache_key.\n *\n * The second callback is called after a connection to a slave is established.\n * It should return it's replication lag or false, if unknown,\n * based on the connection in $wpdb->dbhs[ $wpdb->dbhname ].\n */\n\n/** Sample Configuration 1: Using the Default Server **/\n\n/**\n * This is the most basic way to add a server to HyperDB using only the\n * required parameters: host, user, password, name.\n * This adds the DB defined in wp-config.php as a read/write server for\n * the 'global' dataset. (Every table is in 'global' by default.)\n */\n/*\n$wpdb->add_database(array(\n\t'host'     => DB_HOST,     // If port is other than 3306, use host:port.\n\t'user'     => DB_USER,\n\t'password' => DB_PASSWORD,\n\t'name'     => DB_NAME,\n));\n*/\n\n/**\n * This adds the same server again, only this time it is configured as a slave.\n * The last three parameters are set to the defaults but are shown for clarity.\n */\n/*\n$wpdb->add_database(array(\n\t'host'     => DB_HOST,     // If port is other than 3306, use host:port.\n\t'user'     => DB_USER,\n\t'password' => DB_PASSWORD,\n\t'name'     => DB_NAME,\n\t'write'    => 0,\n\t'read'     => 1,\n\t'dataset'  => 'global',\n\t'timeout'  => 0.2,\n));\n*/\n\n/** Sample Configuration 2: Partitioning **/\n\n/**\n * This example shows a setup where the multisite blog tables have been\n * separated from the global dataset.\n */\n/*\n$wpdb->add_database(array(\n\t'host'     => 'global.db.example.com',\n\t'user'     => 'globaluser',\n\t'password' => 'globalpassword',\n\t'name'     => 'globaldb',\n));\n$wpdb->add_database(array(\n\t'host'     => 'blog.db.example.com',\n\t'user'     => 'bloguser',\n\t'password' => 'blogpassword',\n\t'name'     => 'blogdb',\n\t'dataset'  => 'blog',\n));\n$wpdb->add_callback('my_db_callback');\nfunction my_db_callback($query, $wpdb) {\n\t// Multisite blog tables are \"{$base_prefix}{$blog_id}_*\"\n\tif ( preg_match(\"/^{$wpdb->base_prefix}\\d+_/i\", $wpdb->table) )\n\t\treturn 'blog';\n}\n*/\n\n\n/** Sample helper functions from WordPress.com **/\n\n/**\n * This is back-compatible with an older config style. It is for convenience.\n * lhost, part, and dc were removed from hyperdb because the read and write\n * parameters provide enough power to achieve the desired effects via config.\n *\n * @param string $dataset Datset: the name of the dataset. Just use \"global\" if you don't need horizontal partitioning.\n * @param int $part Partition: the vertical partition number (1, 2, 3, etc.). Use \"0\" if you don't need vertical partitioning.\n * @param string $dc Datacenter: where the database server is located. Airport codes are convenient. Use whatever.\n * @param int $read Read group: tries all servers in lowest number group before trying higher number group. Typical: 1 for slaves, 2 for master. This will cause reads to go to slaves unless all slaves are unreachable. Zero for no reads.\n * @param bool $write Write flag: is this server writable? Works the same as $read. Typical: 1 for master, 0 for slaves.\n * @param string $host Internet address: host:port of server on internet.\n * @param string $lhost Local address: host:port of server for use when in same datacenter. Leave empty if no local address exists.\n * @param string $name Database name.\n * @param string $user Database user.\n * @param string $password Database password.\n */\n/*\nfunction add_db_server($dataset, $part, $dc, $read, $write, $host, $lhost, $name, $user, $password, $timeout = 0.2 ) {\n\tglobal $wpdb;\n\n\t// dc is not used in hyperdb. This produces the desired effect of\n\t// trying to connect to local servers before remote servers. Also\n\t// increases time allowed for TCP responsiveness check.\n\tif ( !empty($dc) && defined(DATACENTER) && $dc != DATACENTER ) {\n\t\tif ( $read )\n\t\t\t$read += 10000;\n\t\tif ( $write )\n\t\t\t$write += 10000;\n\t\t$timeout = 0.7;\n\t}\n\n\t// You'll need a hyperdb::add_callback() callback function to use partitioning.\n\t// $wpdb->add_callback( 'my_func' );\n\tif ( $part )\n\t\t$dataset = $dataset . '_' . $part;\n\n\t$database = compact('dataset', 'read', 'write', 'host', 'name', 'user', 'password', 'timeout');\n\n\t$wpdb->add_database($database);\n\n\t// lhost is not used in hyperdb. This configures hyperdb with an\n\t// additional server to represent the local hostname so it tries to\n\t// connect over the private interface before the public one.\n\tif ( !empty( $lhost ) ) {\n\t\tif ( $read )\n\t\t\t$database['read'] = $read - 0.5;\n\t\tif ( $write )\n\t\t\t$database['write'] = $write - 0.5;\n\t\t$wpdb->add_database( $database );\n\t}\n}\n*/\n\n/**\n * Sample replication lag detection configuration.\n *\n * We use mk-heartbeat (http://www.maatkit.org/doc/mk-heartbeat.html)\n * to detect replication lag.\n *\n * This implementation requires the database user\n * to have read access to the heartbeat table.\n *\n * The cache uses shared memory for portability.\n * Can be modified to work with Memcached, APC and etc.\n */\n\n/*\n\n$wpdb->lag_cache_ttl = 30;\n$wpdb->shmem_key = ftok( __FILE__, \"Y\" );\n$wpdb->shmem_size = 128 * 1024;\n\n$wpdb->add_callback( 'get_lag_cache', 'get_lag_cache' );\n$wpdb->add_callback( 'get_lag',       'get_lag' );\n\nfunction get_lag_cache( $wpdb ) {\n\t$segment = shm_attach( $wpdb->shmem_key, $wpdb->shmem_size, 0600 );\n\t$lag_data = @shm_get_var( $segment, 0 );\n\tshm_detach( $segment );\n\n\tif ( !is_array( $lag_data ) || !is_array( $lag_data[ $wpdb->lag_cache_key ] ) )\n\t\treturn false;\n\n\tif ( $wpdb->lag_cache_ttl < time() - $lag_data[ $wpdb->lag_cache_key ][ 'timestamp' ] )\n\t\treturn false;\n\n\treturn $lag_data[ $wpdb->lag_cache_key ][ 'lag' ];\n}\n\nfunction get_lag( $wpdb ) {\n\t$dbh = $wpdb->dbhs[ $wpdb->dbhname ];\n\n\tif ( !mysql_select_db( 'heartbeat', $dbh ) )\n\t\treturn false;\n\n\t$result = mysql_query( \"SELECT UNIX_TIMESTAMP() - UNIX_TIMESTAMP(ts) AS lag FROM heartbeat LIMIT 1\", $dbh );\n\n\tif ( !$result || false === $row = mysql_fetch_assoc( $result ) )\n\t\treturn false;\n\n\t// Cache the result in shared memory with timestamp\n\t$sem_id = sem_get( $wpdb->shmem_key, 1, 0600, 1 ) ;\n\tsem_acquire( $sem_id );\n\t$segment = shm_attach( $wpdb->shmem_key, $wpdb->shmem_size, 0600 );\n\t$lag_data = @shm_get_var( $segment, 0 );\n\n\tif ( !is_array( $lag_data ) )\n\t\t$lag_data = array();\n\n\t$lag_data[ $wpdb->lag_cache_key ] = array( 'timestamp' => time(), 'lag' => $row[ 'lag' ] );\n\tshm_put_var( $segment, 0, $lag_data );\n\tshm_detach( $segment );\n\tsem_release( $sem_id );\n\n\treturn $row[ 'lag' ];\n}\n\n*/\n\n// The ending PHP tag is omitted. This is actually safer than including it.\n"
  },
  {
    "path": "var/www/html/inactive-plugins/no-uploads.php",
    "content": "<?php\n/**\n* Will be installed into mu-plugins when consul reports NFS container is not healthy\n* Display an error when the NFS container is unavailable.\n*/\nfunction nfs_error_notice() {\n?>\n\n  <div class=\"error notice\">\n      <p><?php esc_html_e( 'The NFS container is not present, media uploads have been disabled'); ?></p>\n  </div>\n\n<?php\n}\nadd_action( 'admin_notices', 'nfs_error_notice' );\n"
  },
  {
    "path": "var/www/html/index.php",
    "content": "<?php\n// WordPress view bootstrapper\ndefine( 'WP_USE_THEMES', true );\nrequire( './wordpress/wp-blog-header.php' );\n"
  },
  {
    "path": "var/www/html/memcached-config.php.ctmpl",
    "content": "<?php\n/**\n * Memcached configuration file\n *\n * This file is automatically generated via a template\n * parsed by consul-template, https://github.com/hashicorp/consul-template .\n *\n * Last update {{timestamp}}\n */\n\n{{ if service \"memcached\" }}\n# turn on WP caching\ndefine('WP_CACHE', true);\ndefine( 'WP_APC_KEY_SALT', '{{env \"WORDPRESS_CACHE_KEY_SALT\"}}' );\ndefine( 'WP_CACHE_KEY_SALT', '{{env \"WORDPRESS_CACHE_KEY_SALT\"}}' );\n\nglobal $memcached_servers;\n\n# write the address:port pairs for each healthy memcached node\n$memcached_servers = array(\n    {{range service \"memcached\"}}\n    \tarray(\n        '{{.Address}}',\n        {{.Port}}\n      ),\n    {{end}}\n);\n{{ end }}\n\n\n// The ending PHP tag is omitted. This is actually safer than including it.\n"
  },
  {
    "path": "var/www/html/wp-cli.yml",
    "content": "path: wordpress/\napache_modules:\n  - mod_rewrite\n"
  },
  {
    "path": "var/www/html/wp-config.php.ctmpl",
    "content": "<?php\n/**\n * WordPress configuration file\n *\n * This file is automatically generated via a template\n * parsed by consul-template, https://github.com/hashicorp/consul-template .\n *\n * Last update {{timestamp}}\n */\n\n/**\n * The following database info is needed here, but is ignored after we load HyperDB.\n * See db-config.php.ctmpl for details.\n */\n ## this is a test\ndefine( 'DB_NAME',     '{{env \"MYSQL_DATABASE\"}}' );\ndefine( 'DB_USER',     '{{env \"MYSQL_USER\"}}' );\ndefine( 'DB_PASSWORD', '{{env \"MYSQL_PASSWORD\"}}' );\ndefine( 'DB_HOST',     '{{if service \"mysql-primary\"}}{{with index (service \"mysql-primary\") 0}}{{.Address}}:{{.Port}}{{end}}{{end}}' );\n\n/**\n * Handle SSL reverse proxy\n */\nif ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') \n{\n    $_SERVER['HTTPS']='on';\n}\n    \n/**\n * Custom Content Directory\n */\ndefine( 'WP_CONTENT_DIR', dirname( __FILE__ ) . '/content' );\ndefine( 'WP_CONTENT_URL', '{{env \"WORDPRESS_URL\"}}/content' );\n\n/**\n * You almost certainly do not want to change these\n */\ndefine( 'DB_CHARSET', 'utf8' );\ndefine( 'DB_COLLATE', '' );\n\n/**\n * Salts, for security\n *\n * Generate random strings in your shell with:\n * tr -dc 'a-zA-Z0-9!@#$%^&*()-_ []{}<>~`+=,.;:/?|' < /dev/urandom | head -c 64\n *\n * On a Mac you'll need to use:\n * LC_ALL=C tr -dc 'a-zA-Z0-9!@#$%^&*()-_ []{}<>~`+=,.;:/?|' < /dev/urandom | head -c 64\n *\n * Props to https://gist.github.com/earthgecko/3089509 for some hints there\n */\ndefine( 'AUTH_KEY',         '{{env \"WORDPRESS_AUTH_KEY\"}}' );\ndefine( 'SECURE_AUTH_KEY',  '{{env \"WORDPRESS_SECURE_AUTH_KEY\"}}' );\ndefine( 'LOGGED_IN_KEY',    '{{env \"WORDPRESS_LOGGED_IN_KEY\"}}' );\ndefine( 'NONCE_KEY',        '{{env \"WORDPRESS_NONCE_KEY\"}}' );\ndefine( 'AUTH_SALT',        '{{env \"WORDPRESS_AUTH_SALT\"}}' );\ndefine( 'SECURE_AUTH_SALT', '{{env \"WORDPRESS_SECURE_AUTH_SALT\"}}' );\ndefine( 'LOGGED_IN_SALT',   '{{env \"WORDPRESS_LOGGED_IN_SALT\"}}' );\ndefine( 'NONCE_SALT',       '{{env \"WORDPRESS_NONCE_SALT\"}}' );\n\n/**\n * Table prefix\n * Change this if you have multiple installs in the same database\n */\n$table_prefix  = 'wp_';\n\n/**\n * Language\n * Leave blank for American English\n */\ndefine( 'WPLANG', '' );\n\n/**\n * Hide errors\n */\nini_set( 'display_errors', {{key_or_default \"wordpress/config/WP_DEBUG_DISPLAY\" \"0\" | parseInt}} );\ndefine( 'WP_DEBUG_DISPLAY', {{key_or_default \"wordpress/config/WP_DEBUG_DISPLAY\" \"0\" | parseBool}} );\n\n/**\n * Debug mode\n * Debugging? Enable these.\n */\n\n/**\n * Load the Memcached config\n */\ninclude( dirname( __FILE__ ) . '/memcached-config.php' );\n\n/**\n * Bootstrap WordPress\n */\nif ( ! defined( 'ABSPATH' ) )\n{\n\tdefine( 'ABSPATH', dirname( __FILE__ ) . '/wordpress/' );\n}\nrequire_once( ABSPATH . 'wp-settings.php' );\n\n// The ending PHP tag is omitted. This is actually safer than including it.\n"
  }
]