diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4cd46d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ + +# Created by https://www.gitignore.io/api/intellij+iml,vim + +### Project Configuration ### +_env + +### Intellij+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### Intellij+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + + +### Vim ### +# swap +[._]*.s[a-w][a-z] +[._]s[a-w][a-z] +# session +Session.vim +# temporary +.netrwhist +*~ +# auto-generated tag files +tags diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..534a539 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,73 @@ +# A minimal HAProxy container including ContainerPilot and a simple virtualhost config +FROM haproxy:latest + +RUN apt-get update && \ + apt-get install --no-install-recommends -qy netcat hatop curl unzip ca-certificates syslog-ng && \ + rm -rf /var/lib/apt/lists/* + +# Install Consul +# Releases at https://releases.hashicorp.com/consul +RUN export CONSUL_VERSION=0.7.0 \ + && export CONSUL_CHECKSUM=b350591af10d7d23514ebaa0565638539900cdb3aaa048f077217c4c46653dd8 \ + && curl --retry 7 --fail -vo /tmp/consul.zip "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip" \ + && echo "${CONSUL_CHECKSUM} /tmp/consul.zip" | sha256sum -c \ + && unzip /tmp/consul -d /usr/local/bin \ + && rm /tmp/consul.zip \ + && mkdir /config + +# Create empty directories for Consul config and data +RUN mkdir -p /etc/consul \ + && mkdir -p /var/lib/consul + +# Install Consul template +# Releases at https://releases.hashicorp.com/consul-template/ +RUN export CONSUL_TEMPLATE_VERSION=0.14.0 \ + && export CONSUL_TEMPLATE_CHECKSUM=7c70ea5f230a70c809333e75fdcff2f6f1e838f29cfb872e1420a63cdf7f3a78 \ + && 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" \ + && echo "${CONSUL_TEMPLATE_CHECKSUM} /tmp/consul-template.zip" | sha256sum -c \ + && unzip /tmp/consul-template.zip -d /usr/local/bin \ + && rm /tmp/consul-template.zip + +# Add Containerpilot and set its configuration +ENV CONTAINERPILOT_VER 2.4.4 +ENV CONTAINERPILOT file:///etc/containerpilot.json + +RUN export CONTAINERPILOT_CHECKSUM=6194ee482dae95844046266dcec2150655ef80e9 \ + && curl -Lso /tmp/containerpilot.tar.gz \ + "https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz" \ + && echo "${CONTAINERPILOT_CHECKSUM} /tmp/containerpilot.tar.gz" | sha1sum -c \ + && tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \ + && rm /tmp/containerpilot.tar.gz + +# Add Dehydrated +RUN export DEHYDRATED_VERSION=v0.3.1 \ + && curl --retry 8 --fail -Lso /tmp/dehydrated.tar.gz "https://github.com/lukas2511/dehydrated/archive/${DEHYDRATED_VERSION}.tar.gz" \ + && tar xzf /tmp/dehydrated.tar.gz -C /tmp \ + && mv /tmp/dehydrated-0.3.1/dehydrated /usr/local/bin \ + && rm -rf /tmp/dehydrated-0.3.1 + +# Add jq +RUN export JQ_VERSION=1.5 \ + && curl --retry 8 --fail -Lso /usr/local/bin/jq "https://github.com/stedolan/jq/releases/download/jq-${JQ_VERSION}/jq-linux64" \ + && chmod a+x /usr/local/bin/jq + +# Consul session data written here +RUN mkdir -p /var/consul + +# Add user and group to run haproxy as +RUN groupadd -g 77 haproxy && \ + useradd -r -m -g 77 -u 77 haproxy && \ + groupadd -g 88 syslog && \ + useradd -r -m -g 88 -u 88 syslog && \ + chown -R syslog:syslog /var/lib/syslog-ng + +COPY etc /etc/ +COPY usr /usr/ + +# /usr/local/bin/containerpilot /usr/local/sbin/haproxy-systemd-wrapper -p /run/haproxy.pid -f /usr/local/etc/haproxy/haproxy.cfg +CMD [ "/usr/local/bin/containerpilot", \ + "/usr/local/sbin/haproxy-systemd-wrapper", \ + "-p", \ + "/run/haproxy.pid", \ + "-f", \ + "/usr/local/etc/haproxy/haproxy.cfg" ] diff --git a/LICENSE b/LICENSE index a612ad9..be2cc4d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,373 +1,362 @@ -Mozilla Public License Version 2.0 -================================== +Mozilla Public License, version 2.0 1. Definitions --------------- 1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. 1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor's Contribution. 1.3. "Contribution" - means Covered Software of a particular Contributor. + + means Covered Software of a particular Contributor. 1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. 1.5. "Incompatible With Secondary Licenses" - means + means - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. + b. that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the terms of + a Secondary License. 1.6. "Executable Form" - means any form of the work other than Source Code Form. + + means any form of the work other than Source Code Form. 1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. + + means a work that combines Covered Software with other material, in a + separate file or files, that is not Covered Software. 1.8. "License" - means this document. + + means this document. 1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. + + means having the right to grant, to the maximum extent possible, whether + at the time of the initial grant or subsequently, any and all of the + rights conveyed by this License. 1.10. "Modifications" - means any of the following: - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or + means any of the following: - (b) any new file in Source Code Form that contains any Covered - Software. + a. any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. + + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the License, + by the making, using, selling, offering for sale, having made, import, + or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" - means the form of the work preferred for making modifications. + + means the form of the work preferred for making modifications. 1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. + + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, "control" means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + 2. License Grants and Conditions --------------------------------- 2.1. Grants -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. 2.2. Effective Date -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. + The licenses granted in Section 2.1 with respect to any Contribution + become effective for each Contribution on the date the Contributor first + distributes such Contribution. 2.3. Limitations on Grant Scope -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: + The licenses granted in this Section 2 are the only rights granted under + this License. No additional rights or licenses will be implied from the + distribution or licensing of Covered Software under this License. + Notwithstanding Section 2.1(b) above, no patent license is granted by a + Contributor: -(a) for any code that a Contributor has removed from Covered Software; - or + a. for any code that a Contributor has removed from Covered Software; or -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or + b. for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. + c. under Patent Claims infringed by Covered Software in the absence of + its Contributions. -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). + This License does not grant any rights in the trademarks, service marks, + or logos of any Contributor (except as may be necessary to comply with + the notice requirements in Section 3.4). 2.4. Subsequent Licenses -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this + License (see Section 10.2) or under the terms of a Secondary License (if + permitted under the terms of Section 3.3). 2.5. Representation -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. + Each Contributor represents that the Contributor believes its + Contributions are its original creation(s) or it has sufficient rights to + grant the rights to its Contributions conveyed by this License. 2.6. Fair Use -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. + This License is not intended to limit any rights You have under + applicable copyright doctrines of fair use, fair dealing, or other + equivalents. 2.7. Conditions -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + 3. Responsibilities -------------------- 3.1. Distribution of Source Form -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under + the terms of this License. You must inform recipients that the Source + Code Form of the Covered Software is governed by the terms of this + License, and how they can obtain a copy of this License. You may not + attempt to alter or restrict the recipients' rights in the Source Code + Form. 3.2. Distribution of Executable Form -If You distribute Covered Software in Executable Form then: + If You distribute Covered Software in Executable Form then: -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. + b. You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter the + recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for + the Covered Software. If the Larger Work is a combination of Covered + Software with a work governed by one or more Secondary Licenses, and the + Covered Software is not Incompatible With Secondary Licenses, this + License permits You to additionally distribute such Covered Software + under the terms of such Secondary License(s), so that the recipient of + the Larger Work may, at their option, further distribute the Covered + Software under the terms of either this License or such Secondary + License(s). 3.4. Notices -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. + You may not remove or alter the substance of any license notices + (including copyright notices, patent notices, disclaimers of warranty, or + limitations of liability) contained within the Source Code Form of the + Covered Software, except that You may alter any license notices to the + extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on + behalf of any Contributor. You must make it absolutely clear that any + such warranty, support, indemnity, or liability obligation is offered by + You alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. 4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, + judicial order, or regulation then You must: (a) comply with the terms of + this License to the maximum extent possible; and (b) describe the + limitations and the code they affect. Such description must be placed in a + text file included with all distributions of the Covered Software under + this License. Except to the extent prohibited by statute or regulation, + such description must be sufficiently detailed for a recipient of ordinary + skill to be able to understand it. 5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing + basis, if such Contributor fails to notify You of the non-compliance by + some reasonable means prior to 60 days after You have come back into + compliance. Moreover, Your grants from a particular Contributor are + reinstated on an ongoing basis if such Contributor notifies You of the + non-compliance by some reasonable means, this is the first time You have + received notice of non-compliance with this License from such + Contributor, and You become compliant prior to 30 days after Your receipt + of the notice. 5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ + infringement claim (excluding declaratory judgment actions, + counter-claims, and cross-claims) alleging that a Contributor Version + directly or indirectly infringes any patent, then the rights granted to + You by any and all Contributors for the Covered Software under Section + 2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an "as is" basis, + without warranty of any kind, either expressed, implied, or statutory, + including, without limitation, warranties that the Covered Software is free + of defects, merchantable, fit for a particular purpose or non-infringing. + The entire risk as to the quality and performance of the Covered Software + is with You. Should any Covered Software prove defective in any respect, + You (not any Contributor) assume the cost of any necessary servicing, + repair, or correction. This disclaimer of warranty constitutes an essential + part of this License. No use of any Covered Software is authorized under + this License except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from + such party's negligence to the extent applicable law prohibits such + limitation. Some jurisdictions do not allow the exclusion or limitation of + incidental or consequential damages, so this exclusion and limitation may + not apply to You. 8. Litigation -------------- -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. + Any litigation relating to this License may be brought only in the courts + of a jurisdiction where the defendant maintains its principal place of + business and such litigation shall be governed by laws of that + jurisdiction, without reference to its conflict-of-law provisions. Nothing + in this Section shall prevent a party's ability to bring cross-claims or + counter-claims. 9. Miscellaneous ----------------- -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. + This License represents the complete agreement concerning the subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. Any law or regulation which provides that + the language of a contract shall be construed against the drafter shall not + be used to construe this License against a Contributor. + 10. Versions of the License ---------------------------- 10.1. New Versions -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. 10.2. Effect of New Versions -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. + You may distribute the Covered Software under the terms of the version + of the License under which You originally received the Covered Software, + or under the terms of any subsequent version published by the license + steward. 10.3. Modified Versions -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a + modified version of this License if you rename the license and remove + any references to the name of the license steward (except to note that + such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. + Licenses If You choose to distribute Source Code Form that is + Incompatible With Secondary Licenses under the terms of this version of + the License, the notice described in Exhibit B of this License must be + attached. Exhibit A - Source Code Form License Notice -------------------------------------------- - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. +If it is not possible or desirable to put the notice in a particular file, +then You may include the notice in a location (such as a LICENSE file in a +relevant directory) where a recipient would be likely to look for such a +notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. + This Source Code Form is "Incompatible + With Secondary Licenses", as defined by + the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md index c1806e6..0f9a6d4 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ -# haproxy -Work in progress, not stable, expect force pushes of this repo +# Autopilot Pattern HAProxy + +*A re-usable HAProxy base image implemented according to the +[Autopilot Pattern](http://autopilotpattern.io/) for automatic discovery and configuration.* + +[![DockerPulls](https://img.shields.io/docker/pulls/dekobon/haproxy.svg)](https://registry.hub.docker.com/u/dekobon/haproxy/) +[![DockerStars](https://img.shields.io/docker/stars/dekobon/haproxy.svg)](https://registry.hub.docker.com/u/dekobon/haproxy/) + +### A reusable HAProxy container image + +The goal of this project is to create a HAProxy image that can be reused across +environments without having to rebuild the entire image. Configuration of +HAProxy is entirely via ContainerPilot `preStart` or `onChange` handlers. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e89dd62 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,52 @@ +# Autopilot Haproxy demo +# +# For most use cases, it's better to build a custom image using this Haproxy base image + +haproxy: + image: dekobon/haproxy + restart: always + mem_limit: 512m + env_file: _env + environment: + - BACKEND=example + - CONSUL_AGENT=1 + - ACME_ENV=staging + ports: + - 80 + - 443 + - 9090 # so we can see telemetry + labels: + - triton.cns.services=haproxy + +example: + image: autopilotpattern/nginx-example-app + mem_limit: 128m + env_file: _env + environment: + - CONSUL_AGENT=1 + expose: + - 4000 # not strictly necessary because we don't link + restart: always + labels: + - triton.cns.services=example + +# Start with a single host which will bootstrap the cluster. +# In production we'll want to use an HA cluster. +consul: + image: consul:v0.7.0 + restart: always + mem_limit: 128m + expose: + - 53 + - 8300 + - 8301 + - 8302 + - 8400 + - 8500 + ports: + - 8500 + dns: + - 127.0.0.1 + labels: + - triton.cns.services=consul + command: agent -server -client=0.0.0.0 -bootstrap -ui diff --git a/etc/containerpilot.json b/etc/containerpilot.json new file mode 100644 index 0000000..050b8f1 --- /dev/null +++ b/etc/containerpilot.json @@ -0,0 +1,42 @@ +{ + "consul": "{{ if .CONSUL_AGENT }}localhost{{ else }}{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}{{ end }}:8500", + "preStart": "/usr/local/bin/reload.sh preStart", + "logging": {"level": "DEBUG"}, + "services": [ + { + "name": "haproxy", + "port": 80, + "health": "/usr/bin/curl --fail --silent --show-error --output /dev/null http://localhost:9090", + "poll": 10, + "ttl": 25, + "interfaces": ["eth0"] + } + ], + "backends": [ + { + "name": "{{ .BACKEND }}", + "poll": 7, + "onChange": "/usr/local/bin/reload.sh" + } + ], + "coprocesses": [{{ if .CONSUL_AGENT }} + { + "command": ["/usr/local/bin/consul", "agent", + "-data-dir=/var/lib/consul", + "-config-dir=/etc/consul", + "-rejoin", + "-retry-join", "{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}", + "-retry-max", "10", + "-retry-interval", "10s"], + "restarts": "unlimited" + },{{ end }} + { + "name": "syslog", + "restarts": "unlimited", + "command": ["/usr/sbin/syslog-ng", + "--no-caps", + "--worker-threads=1", + "-F"] + } + ] +} diff --git a/etc/syslog-ng/syslog-ng.conf b/etc/syslog-ng/syslog-ng.conf new file mode 100644 index 0000000..9f9b479 --- /dev/null +++ b/etc/syslog-ng/syslog-ng.conf @@ -0,0 +1,47 @@ +@version: 3.5 +@include "scl.conf" +@include "`scl-root`/system/tty10.conf" + +# Syslog-ng configuration file, compatible with default Debian syslogd +# installation. + +# First, set some global options. +options { chain_hostnames(off); flush_lines(0); use_dns(no); use_fqdn(no); + owner("syslog"); group("syslog"); perm(0640); stats_freq(0); + keep_hostname(no); + bad_hostname("^gconfd$"); +}; + +######################## +# Sources +######################## +# This is the default behavior of sysklogd package +# Logs may come from unix stream, but not from another machine. +# +source s_src { + internal(); + + network( + ip(127.0.0.1) + transport("udp") + port(514) + ); +}; + +destination d_docker_console { + file("/dev/console", + template("${YEAR}/${MONTH}/${DAY} ${HOUR}:${MIN}:${SEC} ${PROGRAM} ${MSGONLY}\n")); +}; + +######################## +# Log paths +######################## + + +# All messages go to console +log { source(s_src); destination(d_docker_console); }; + +### +# Include all config files in /etc/syslog-ng/conf.d/ +### +@include "/etc/syslog-ng/conf.d/*.conf" diff --git a/example-backend/Dockerfile b/example-backend/Dockerfile new file mode 100755 index 0000000..3d90db7 --- /dev/null +++ b/example-backend/Dockerfile @@ -0,0 +1,42 @@ +# a Node.js application container including ContainerPilot +FROM gliderlabs/alpine:3.3 + +# install curl +RUN apk update && apk add \ + nodejs \ + curl \ + && rm -rf /var/cache/apk/* + +# install the Express.js dependency +COPY package.json /opt/example/ +RUN cd /opt/example && npm install + +# Add Consul from https://releases.hashicorp.com/consul +RUN export CONSUL_VERSION=0.7.0 \ + && export CONSUL_CHECKSUM=b350591af10d7d23514ebaa0565638539900cdb3aaa048f077217c4c46653dd8 \ + && curl --retry 7 --fail -vo /tmp/consul.zip "https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip" \ + && echo "${CONSUL_CHECKSUM} /tmp/consul.zip" | sha256sum -c \ + && unzip /tmp/consul -d /usr/local/bin \ + && rm /tmp/consul.zip \ + && mkdir /config + +# Add Containerpilot and set its configuration +ENV CONTAINERPILOT_VER 2.4.3 +ENV CONTAINERPILOT file:///etc/containerpilot.json + +RUN export CONTAINERPILOT_CHECKSUM=2c469a0e79a7ac801f1c032c2515dd0278134790 \ + && curl -Lso /tmp/containerpilot.tar.gz \ + "https://github.com/joyent/containerpilot/releases/download/${CONTAINERPILOT_VER}/containerpilot-${CONTAINERPILOT_VER}.tar.gz" \ + && echo "${CONTAINERPILOT_CHECKSUM} /tmp/containerpilot.tar.gz" | sha1sum -c \ + && tar zxf /tmp/containerpilot.tar.gz -C /usr/local/bin \ + && rm /tmp/containerpilot.tar.gz + +# add our application and configuration +COPY example.js /opt/example/ +COPY containerpilot.json /etc + +EXPOSE 4000 +CMD [ "/usr/local/bin/containerpilot", \ + "node", \ + "/opt/example/example.js" \ +] diff --git a/example-backend/containerpilot.json b/example-backend/containerpilot.json new file mode 100755 index 0000000..135aa9f --- /dev/null +++ b/example-backend/containerpilot.json @@ -0,0 +1,23 @@ +{ + "consul": "{{ if .CONSUL_AGENT }}localhost{{ else }}{{ if .CONSUL }}{{ .CONSUL }}{{ else }}consul{{ end }}{{ end }}:8500", + "services": [ + { + "name": "example", + "port": 4000, + "health": "/usr/bin/curl -o /dev/null --fail -s http://localhost:4000/", + "poll": 3, + "ttl": 10 + } + ], + "coprocesses": [{{ if .CONSUL_AGENT }} + { + "command": ["/usr/local/bin/consul", "agent", + "-data-dir=/data", + "-config-dir=/config", + "-rejoin", + "-retry-join", "{{ .CONSUL }}", + "-retry-max", "10", + "-retry-interval", "10s"], + "restarts": "unlimited" + }{{ end }}] +} diff --git a/example-backend/example.js b/example-backend/example.js new file mode 100755 index 0000000..4c26f53 --- /dev/null +++ b/example-backend/example.js @@ -0,0 +1,31 @@ +var express = require('express'); + +var app = express(); + +// An array of quotes; source: http://www.journaldev.com/240/my-25-favorite-programming-quotes-that-are-funny-too +var quotes = [ + "The best thing about a boolean is even if you are wrong, you are only off by a bit. (Anonymous)", + "Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)", + "Before software can be reusable it first has to be usable. (Ralph Johnson)", + "There are two ways to write error-free programs; only the third one works. (Alan J. Perlis)", + "One [person's] crappy software is another [person's] full time job. (Jessica Gaston)", + "A good programmer is someone who always looks both ways before crossing a one-way street. (Doug Linder)", + "Always code as if the [person] who ends up maintaining your code will be a violent psychopath who knows where you live. (Martin Golding)", + "Deleted code is debugged code. (Jeff Sickel)", + "Walking on water and developing software from a specification are easy if both are frozen. (Edward V Berard)", + "If debugging is the process of removing software bugs, then programming must be the process of putting them in. (Edsger Dijkstra)", + "In order to understand recursion, one must first understand recursion. (Anonymous)", + "The cheapest, fastest, and most reliable components are those that aren’t there. (Gordon Bell)", + "The best performance improvement is the transition from the nonworking state to the working state. (J. Osterhout)" +]; + +// Return a random quote for all requests to the web root +app.get('*', function (req, res) { + res.setHeader('Content-Type', 'text/html'); + var quote = quotes[Math.floor(Math.random()*quotes.length)]; + res.send(quote); +}); + +app.listen(4000, function () { + console.log('Running Example app on port 4000'); +}); diff --git a/example-backend/package.json b/example-backend/package.json new file mode 100755 index 0000000..e00b069 --- /dev/null +++ b/example-backend/package.json @@ -0,0 +1,14 @@ +{ + "name": "example", + "version": "1.0.0", + "description": "", + "main": "example.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Casey Bisson, Joyent", + "license": "Mozilla Public License 2.0", + "dependencies": { + "express": "^4.13.4" + } +} diff --git a/local-compose.yml b/local-compose.yml new file mode 100644 index 0000000..c4c7408 --- /dev/null +++ b/local-compose.yml @@ -0,0 +1,36 @@ +haproxy: + extends: + file: docker-compose.yml + service: haproxy +# build: . + mem_limit: 128m + environment: + - CONSUL=consul + - CONSUL_AGENT=1 + - ACME_ENV=staging + links: + - consul:consul + ports: + - 80:80 + - 443:443 + - 9090:9090 # telemetry endpoint + +example: + extends: + file: docker-compose.yml + service: example + build: example-backend/ + environment: + - CONSUL=consul + - CONSUL_AGENT=1 + links: + - consul:consul + ports: + - 4000:4000 + +consul: + extends: + file: docker-compose.yml + service: consul + ports: + - 8500:8500 diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..dd9b195 --- /dev/null +++ b/setup.sh @@ -0,0 +1,129 @@ +#!/bin/bash +set -e -o pipefail + +help() { + echo 'Usage ./setup.sh [-f docker-compose.yml] [-p project]' + echo + echo 'Checks that your Triton and Docker environment is sane and configures' + echo 'an environment file to use.' + echo + echo 'Optional flags:' + echo ' -f use this file as the docker-compose config file' + echo ' -p use this name as the project prefix for docker-compose' +} + + +# default values which can be overriden by -f or -p flags +export COMPOSE_PROJECT_NAME=haproxy +export COMPOSE_FILE= + +# give the docker remote api more time before timeout +export COMPOSE_HTTP_TIMEOUT=300 + +# populated by `check` function whenever we're using Triton +TRITON_USER= +TRITON_DC= +TRITON_ACCOUNT= + +# --------------------------------------------------- +# Top-level commmands + + +# Check for correct configuration +check() { + + command -v docker >/dev/null 2>&1 || { + echo + tput rev # reverse + tput bold # bold + echo 'Docker is required, but does not appear to be installed.' + tput sgr0 # clear + echo 'See https://docs.joyent.com/public-cloud/api-access/docker' + exit 1 + } + command -v json >/dev/null 2>&1 || { + echo + tput rev # reverse + tput bold # bold + echo 'Error! JSON CLI tool is required, but does not appear to be installed.' + tput sgr0 # clear + echo 'See https://apidocs.joyent.com/cloudapi/#getting-started' + exit 1 + } + + # if we're not testing on Triton, don't bother checking Triton config + if [ ! -z "${COMPOSE_FILE}" ]; then + exit 0 + fi + + command -v triton >/dev/null 2>&1 || { + echo + tput rev # reverse + tput bold # bold + echo 'Error! Joyent Triton CLI is required, but does not appear to be installed.' + tput sgr0 # clear + echo 'See https://www.joyent.com/blog/introducing-the-triton-command-line-tool' + exit 1 + } + + # make sure Docker client is pointed to the same place as the Triton client + local docker_user=$(docker info 2>&1 | awk -F": " '/SDCAccount:/{print $2}') + local docker_dc=$(echo $DOCKER_HOST | awk -F"/" '{print $3}' | awk -F'.' '{print $1}') + TRITON_USER=$(triton profile get | awk -F": " '/account:/{print $2}') + TRITON_DC=$(triton profile get | awk -F"/" '/url:/{print $3}' | awk -F'.' '{print $1}') + TRITON_ACCOUNT=$(triton account get | awk -F": " '/id:/{print $2}') + if [ ! "$docker_user" = "$TRITON_USER" ] || [ ! "$docker_dc" = "$TRITON_DC" ]; then + echo + tput rev # reverse + tput bold # bold + echo 'Error! The Triton CLI configuration does not match the Docker CLI configuration.' + tput sgr0 # clear + echo + echo "Docker user: ${docker_user}" + echo "Triton user: ${TRITON_USER}" + echo "Docker data center: ${docker_dc}" + echo "Triton data center: ${TRITON_DC}" + exit 1 + fi + + local triton_cns_enabled=$(triton account get | awk -F": " '/cns/{print $2}') + if [ ! "true" == "$triton_cns_enabled" ]; then + echo + tput rev # reverse + tput bold # bold + echo 'Error! Triton CNS is required and not enabled.' + tput sgr0 # clear + echo + exit 1 + fi + + echo CONSUL=consul.svc.${TRITON_ACCOUNT}.${TRITON_DC}.cns.joyent.com > _env +} + +# --------------------------------------------------- +# parse arguments + +while getopts "f:p:h" optchar; do + case "${optchar}" in + f) export COMPOSE_FILE=${OPTARG} ;; + p) export COMPOSE_PROJECT_NAME=${OPTARG} ;; + esac +done +shift $(expr $OPTIND - 1 ) + +until + cmd=$1 + if [ ! -z "$cmd" ]; then + shift 1 + $cmd "$@" + if [ $? == 127 ]; then + help + fi + exit + fi +do + echo +done + +# default behavior +check diff --git a/usr/local/bin/reload.sh b/usr/local/bin/reload.sh new file mode 100755 index 0000000..938e86c --- /dev/null +++ b/usr/local/bin/reload.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +SERVICE_NAME=${SERVICE_NAME:-haproxy} +CONSUL=${CONSUL:-consul} +CERT_DIR="/var/www/ssl" + +# Render Nginx configuration template using values from Consul, +# but do not reload because HAProxy has't started yet +preStart() { + removeCruft + writeConfiguration +} + +# Render HAProxy configuration template using values from Consul, +# then gracefully reload HAProxy +onChange() { +# local SSL_READY="false" +# if [ -f ${CERT_DIR}/fullchain.pem -a -f ${CERT_DIR}/privkey.pem ]; then +# SSL_READY="true" +# fi +# export SSL_READY + + writeConfiguration + kill -s SIGHUP $(pgrep -f '^/usr/local/sbin/haproxy-systemd-wrapper') +} + +writeConfiguration() { + echo "Writing HAProxy to /tmp/haproxy.cfg" + + consul-template \ + -once \ + -dedup \ + -consul ${CONSUL}:8500 \ + -template "/usr/local/etc/haproxy/haproxy.cfg.ctmpl:/usr/local/etc/haproxy/haproxy.cfg" +} + +removeCruft() { + if [ -f /run/haproxy.pid ]; then + echo "Removing PID file left over after container shutdown" + rm -f /run/haproxy.pid + fi +} + +help() { + echo "Usage: ./reload.sh preStart => first-run configuration for HAProxy" + echo " ./reload.sh onChange => [default] update HAProxy config on upstream changes" +} + +until + cmd=$1 + if [ -z "$cmd" ]; then + onChange + fi + shift 1 + $cmd "$@" + [ "$?" -ne 127 ] +do + onChange + exit +done diff --git a/usr/local/etc/haproxy/haproxy.cfg.ctmpl b/usr/local/etc/haproxy/haproxy.cfg.ctmpl new file mode 100644 index 0000000..7c53979 --- /dev/null +++ b/usr/local/etc/haproxy/haproxy.cfg.ctmpl @@ -0,0 +1,55 @@ +# This is an example HAProxy configuration template file. +# Adjust the values below as required for your application. + +global + description HAProxy on autopilot + user haproxy + group haproxy + log 127.0.0.1:514 syslog info + maxconn 4096 + stats socket /var/run/haproxy.sock mode 600 level admin + stats timeout 2m #Wait up to 2 minutes for input + +defaults + log global + mode http + option httplog + option dontlognull + option forwardfor + option tcp-smart-accept + option tcp-smart-connect + option http-keep-alive + option http-server-close + + timeout http-request 10s + timeout client 10s + timeout connect 2s + timeout server 15s + + retries 3 + + # Make sure there is no message outputted to browsers when they time out + errorfile 408 /dev/null + +frontend http-in + bind *:80 + + # Don't let the client set this + reqidel ^X-Forwarded-For:.*$ + reqidel ^X-Real-IP:.*$ + + reqadd X-Forwarded-Proto:\ http + + use_backend autopilot + +backend autopilot + balance roundrobin + + http-request set-header X-Forwarded-Port %[dst_port] + http-request add-header X-Forwarded-Proto https if { ssl_fc } + +{{ $backend := env "BACKEND" }}{{ if service $backend }} + # write the address:port pairs for each healthy backend instance{{range service $backend }} + server {{.ID}} {{.Address}}:{{.Port}} + {{end}} +{{ end }}