diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ac26948 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +config/*.yml -whitespace +releases/*.yml -whitespace diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..efccb5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +config/dev.yml +config/private.yml +releases/*.tgz +dev_releases +blobs +.blobs +.dev_builds +.idea +.final_builds/jobs/**/*.tgz +.final_builds/packages/**/*.tgz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8e5942e --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2014] [Pivotal Software, Inc] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..c1059fa --- /dev/null +++ b/README.md @@ -0,0 +1,153 @@ +# CF-BOSH Release containing several jobs to configure VM networking + +This [CF-BOSH](http://docs.cloudfoundry.org/bosh/) release contains several jobs to help you configure VMs with +special networking properties: + +* [Gateway](https://github.com/cf-platform-eng/networking-boshrelease/tree/master/jobs/gateway): allows to add a [default gateway](http://en.wikipedia.org/wiki/Default_gateway) to your vms +* [NAT](https://github.com/cf-platform-eng/networking-boshrelease/tree/master/jobs/nat): allows to create a [NAT](http://en.wikipedia.org/wiki/Network_address_translation) vm using [iptables](http://en.wikipedia.org/wiki/Iptables) +* [Routes](https://github.com/cf-platform-eng/networking-boshrelease/tree/master/jobs/routes): allows to add [IP routes](http://en.wikipedia.org/wiki/Routing_table) to your vms + +## Usage + +### Upload the BOSH release + +To use this bosh release, first upload it to your bosh: + +``` shell +bosh target BOSH_HOST +git clone https://github.com/cf-platform-eng/networking-boshrelease.git +cd networking-boshrelease +bosh upload release releases/networking/networking-1.yml +``` + +### Add the release to your BOSH deployment manifest + +Add the appropriate release jobs and properties to your BOSH deployment manifest: + +``` yaml +--- +releases: + - name: cf + version: latest + - name: networking + version: latest + +... + +jobs: + - name: haproxy + templates: + - name: nat + release: networking + - name: haproxy + release: cf + instances: 1 + resource_pool: default + networks: + - name: default + default: [dns, gateway] + - name: public + static_ips: + - 1.2.3.4 + - name: router + templates: + - name: gateway + release: networking + - name: routes + release: networking + - name: gorouter + release: cf + +... + +properties: + networking: + nat: + in_interface: eth0 + out_interface: eth1 + gateway: + default: 0.haproxy.default.cf.microbosh + routes: + - net: 192.168.1.0 + netmask: 255.255.255.224 + interface: eth0 +``` + +### Deploy using the BOSH deployment manifest + +Using the previous created deployment manifest, now we can deploy it: + +``` shell +bosh deployment path/to/deployment.yml +bosh -n deploy +``` + +## Contributing + +In the spirit of [free software](http://www.fsf.org/licensing/essays/free-sw.html), **everyone** is encouraged to help improve this project. + +Here are some ways *you* can contribute: + +* by using alpha, beta, and prerelease versions +* by reporting bugs +* by suggesting new features +* by writing or editing documentation +* by writing specifications +* by writing code (**no patch is too small**: fix typos, add comments, clean up inconsistent whitespace) +* by refactoring code +* by closing [issues](https://github.com/cf-platform-eng/networking-boshrelease/issues) +* by reviewing patches + + +### Submitting an Issue +We use the [GitHub issue tracker](https://github.com/cf-platform-eng/networking-boshrelease/issues) to track bugs and features. +Before submitting a bug report or feature request, check to make sure it hasn't already been submitted. +You can indicate support for an existing issue by voting it up. +When submitting a bug report, please include a [Gist](http://gist.github.com/) that includes a stack trace and any +details that may be necessary to reproduce the bug, including your gem version, Ruby version, and operating system. +Ideally, a bug report should include a pull request with failing specs. + +### Submitting a Pull Request + +1. Fork the project. +2. Create a topic branch. +3. Implement your feature or bug fix. +4. Commit and push your changes. +5. Submit a pull request. + +### Create new release + +#### Creating a final release + +If you need to create a new final release, you will need to get read/write API credentials to the [@cloudfoundry-community](https://github.com/cloudfoundry-community) s3 account. + +Please email [Dr Nic Williams](mailto:drnicwilliams@gmail.com) and he will create unique API credentials for you. + +Create a `config/private.yml` file with the following contents: + +``` yaml +--- +blobstore: + s3: + access_key_id: ACCESS + secret_access_key: PRIVATE +``` + +You can now create final releases for everyone to enjoy! + +``` shell +bosh create release +# test this dev release +git commit -m "updated networking bosh release" +bosh create release --final +git commit -m "creating vXYZ release" +git tag vXYZ +git push origin master --tags +``` + +## Copyright + +See [LICENSE](https://github.com/cf-platform-eng/networking-boshrelease/blob/master/LICENSE) for details. +Copyright (c) 2014 [Pivotal Software, Inc](http://www.pivotal.io/). + +Based on the [Rakuten BOSH routing release](https://github.com/rakutentech/bosh-routing-release). diff --git a/config/.gitkeep b/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/config/blobs.yml b/config/blobs.yml new file mode 100644 index 0000000..2fbf0ff --- /dev/null +++ b/config/blobs.yml @@ -0,0 +1 @@ +--- {} diff --git a/config/final.yml b/config/final.yml new file mode 100644 index 0000000..f3f6c9d --- /dev/null +++ b/config/final.yml @@ -0,0 +1,9 @@ +--- +final_name: networking +blobstore: + provider: s3 + options: + bucket_name: networking-boshrelease + access_key_id: AKIAJPWUHOHV42IMTNQQ + secret_access_key: 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 + encryption_key: cloudfoundry-community diff --git a/jobs/.gitkeep b/jobs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/jobs/gateway/monit b/jobs/gateway/monit new file mode 100644 index 0000000..003159a --- /dev/null +++ b/jobs/gateway/monit @@ -0,0 +1,5 @@ +check file gateway + with path /var/vcap/sys/run/gateway/gateway.check + start program "/var/vcap/packages/bosh-helpers/monit_debugger gateway_ctl '/var/vcap/jobs/gateway/bin/gateway_ctl start'" + stop program "/var/vcap/packages/bosh-helpers/monit_debugger gateway_ctl '/var/vcap/jobs/gateway/bin/gateway_ctl stop'" + group vcap diff --git a/jobs/gateway/spec b/jobs/gateway/spec new file mode 100644 index 0000000..ba89f04 --- /dev/null +++ b/jobs/gateway/spec @@ -0,0 +1,13 @@ +--- +name: gateway + +packages: + - bosh-helpers + +templates: + bin/gateway_ctl.erb: bin/gateway_ctl + bin/job_properties.sh.erb: bin/job_properties.sh + +properties: + networking.gateway.default: + description: "Default gateway" diff --git a/jobs/gateway/templates/bin/gateway_ctl.erb b/jobs/gateway/templates/bin/gateway_ctl.erb new file mode 100644 index 0000000..15bf20a --- /dev/null +++ b/jobs/gateway/templates/bin/gateway_ctl.erb @@ -0,0 +1,78 @@ +#!/bin/bash + +set -e # exit immediately if a simple command exits with a non-zero status + +# Setup common env vars and folders +source /var/vcap/packages/bosh-helpers/ctl_setup.sh 'gateway' + +lookup_hostname() { + if [[ ${1} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then + echo ${1} + else + ip=$(dig +short ${1}) + if [ -n "${ip}" ]; then + echo ${ip} + fi + fi +} + +list_default_gateway() { + echo "*** $(date) Current default gateways:" + set +e + /sbin/ip route show | grep default + set -e +} + +update_default_gateway() { + list_default_gateway + + echo "*** $(date) ${1} default gateway:" + gateway=$(lookup_hostname ${2}) + if [ -n "${gateway}" ];then + set +e + route --verbose ${1} default gw ${gateway} + set -e + else + echo "Could not resolve hostname ${2}" + return 1 + fi + + list_default_gateway +} + +case $1 in + + start) + echo "****** $(date) ${0} start" + + # Update default gateway + update_default_gateway add <%= p('networking.gateway.default') %> + + # Create check file + touch ${GATEWAY_PID_DIR}/gateway.check + ;; + + stop) + echo "****** $(date) ${0} stop" + + # Update default gateway + update_default_gateway del <%= p('networking.gateway.default') %> + + # Remove check file + rm ${GATEWAY_PID_DIR}/gateway.check + ;; + + status) + echo "****** $(date) ${0} status" + + # List default gateway + list_default_gateway + ;; + + *) + echo "Usage: $0 {start|stop|status}" + exit 1 + ;; + +esac +exit 0 diff --git a/jobs/gateway/templates/bin/job_properties.sh.erb b/jobs/gateway/templates/bin/job_properties.sh.erb new file mode 100644 index 0000000..37bfd77 --- /dev/null +++ b/jobs/gateway/templates/bin/job_properties.sh.erb @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# +# Gateway job properties +# + +# Directory to store the Gateway job configuration files +export GATEWAY_CONF_DIR=${JOB_DIR}/config + +# Directory to store the Gateway job log files +export GATEWAY_LOG_DIR=${LOG_DIR} + +# Directory to store the Gateway job process IDs +export GATEWAY_PID_DIR=${RUN_DIR} + +# Directory to store the Gateway job data files +export GATEWAY_STORE_DIR=${STORE_DIR} + +# Directory to store the Gateway job temp files +export GATEWAY_TMP_DIR=${TMP_DIR} diff --git a/jobs/nat/monit b/jobs/nat/monit new file mode 100644 index 0000000..ed1f8e2 --- /dev/null +++ b/jobs/nat/monit @@ -0,0 +1,5 @@ +check file nat + with path /var/vcap/sys/run/nat/nat.check + start program "/var/vcap/packages/bosh-helpers/monit_debugger nat_ctl '/var/vcap/jobs/nat/bin/nat_ctl start'" + stop program "/var/vcap/packages/bosh-helpers/monit_debugger nat_ctl '/var/vcap/jobs/nat/bin/nat_ctl stop'" + group vcap diff --git a/jobs/nat/spec b/jobs/nat/spec new file mode 100644 index 0000000..94c328e --- /dev/null +++ b/jobs/nat/spec @@ -0,0 +1,17 @@ +--- +name: nat + +packages: + - bosh-helpers + +templates: + bin/job_properties.sh.erb: bin/job_properties.sh + bin/nat_ctl.erb: bin/nat_ctl + +properties: + networking.nat.in_interface: + description: "Input interface to forward packets" + default: "eth0" + networking.nat.out_interface: + description: "Output interface to forward packets" + default: "eth1" diff --git a/jobs/nat/templates/bin/job_properties.sh.erb b/jobs/nat/templates/bin/job_properties.sh.erb new file mode 100644 index 0000000..24bc668 --- /dev/null +++ b/jobs/nat/templates/bin/job_properties.sh.erb @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# +# NAT job properties +# + +# Directory to store the NAT job configuration files +export NAT_CONF_DIR=${JOB_DIR}/config + +# Directory to store the NAT job log files +export NAT_LOG_DIR=${LOG_DIR} + +# Directory to store the NAT job process IDs +export NAT_PID_DIR=${RUN_DIR} + +# Directory to store the NAT job data files +export NAT_STORE_DIR=${STORE_DIR} + +# Directory to store the NAT job temp files +export NAT_TMP_DIR=${TMP_DIR} diff --git a/jobs/nat/templates/bin/nat_ctl.erb b/jobs/nat/templates/bin/nat_ctl.erb new file mode 100644 index 0000000..b5fd5d8 --- /dev/null +++ b/jobs/nat/templates/bin/nat_ctl.erb @@ -0,0 +1,98 @@ +#!/bin/bash + +set -e # exit immediately if a simple command exits with a non-zero status + +# Setup common env vars and folders + +source /var/vcap/packages/bosh-helpers/ctl_setup.sh 'nat' +list_ip_forwarding() { + ip_forwarding=$(cat /proc/sys/net/ipv4/ip_forward) + echo "*** $(date) Current ip forwarding status: ${ip_forwarding}" +} + +update_ip_forwarding() { + list_ip_forwarding + + echo "*** $(date) Updating ip forwarding with: ${1}" + echo ${1} > /proc/sys/net/ipv4/ip_forward + + list_ip_forwarding +} + +list_iptable_rules() { + echo "*** $(date) Current iptable rules:" + /sbin/iptables --verbose --list + /sbin/iptables --verbose --list --table nat +} + +update_iptable_rules() { + list_iptable_rules + + echo "*** $(date) ${1} iptable rules:" + set +e + /sbin/iptables --verbose \ + --${1} POSTROUTING \ + --table nat \ + --out-interface <%= p('networking.nat.out_interface') %> \ + --jump MASQUERADE + /sbin/iptables --verbose \ + --${1} FORWARD \ + --in-interface <%= p('networking.nat.out_interface') %> \ + --out-interface <%= p('networking.nat.in_interface') %> \ + --match state --state RELATED,ESTABLISHED \ + --jump ACCEPT + /sbin/iptables --verbose \ + --${1} FORWARD \ + --in-interface <%= p('networking.nat.in_interface') %> \ + --out-interface <%= p('networking.nat.out_interface') %> \ + --jump ACCEPT + set -e + + list_iptable_rules +} + +case $1 in + + start) + echo "****** $(date) ${0} start" + + # Enable IP forwarding + update_ip_forwarding 1 + + # Enable iptable rules + update_iptable_rules 'append' + + # Create check file + touch ${NAT_PID_DIR}/nat.check + ;; + + stop) + echo "****** $(date) ${0} stop" + + # Disable iptable rules + update_iptable_rules 'delete' + + # Disable IP forwarding + update_ip_forwarding 0 + + # Remove check file + rm ${NAT_PID_DIR}/nat.check + ;; + + status) + echo "****** $(date) ${0} status" + + # List ip forwarding status + list_ip_forwarding + + # List iptable rules + list_iptable_rules + ;; + + *) + echo "Usage: ${0} {start|stop|status}" + exit 1 + ;; + +esac +exit 0 diff --git a/jobs/routes/monit b/jobs/routes/monit new file mode 100644 index 0000000..07bec47 --- /dev/null +++ b/jobs/routes/monit @@ -0,0 +1,5 @@ +check file routes + with path /var/vcap/sys/run/routes/routes.check + start program "/var/vcap/packages/bosh-helpers/monit_debugger routes_ctl '/var/vcap/jobs/routes/bin/routes_ctl start'" + stop program "/var/vcap/packages/bosh-helpers/monit_debugger routes_ctl '/var/vcap/jobs/routes/bin/routes_ctl stop'" + group vcap diff --git a/jobs/routes/spec b/jobs/routes/spec new file mode 100644 index 0000000..4ca3387 --- /dev/null +++ b/jobs/routes/spec @@ -0,0 +1,23 @@ +--- +name: routes + +packages: + - bosh-helpers + +templates: + bin/job_properties.sh.erb: bin/job_properties.sh + bin/routes_ctl.erb: bin/routes_ctl + +properties: + networking.routes: + description: "List of routes to be added" + # Properties of each route item: + # net: the destination network + # host: the destination host + # netmask: when adding a network route, the netmask to be used + # gateway: route packets via a gateway + # metric: the metric field in the routing table to M. + # mss: the TCP Maximum Segment Size (MSS) for connections over this route to M bytes + # window: the TCP window size for connections over this route to W bytes + # irtt: the initial round trip time (irtt) for TCP connections over this route to I milliseconds (1-12000) + # interface: force the route to be associated with the specified device diff --git a/jobs/routes/templates/bin/job_properties.sh.erb b/jobs/routes/templates/bin/job_properties.sh.erb new file mode 100644 index 0000000..bd532dd --- /dev/null +++ b/jobs/routes/templates/bin/job_properties.sh.erb @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# +# Routes job properties +# + +# Directory to store the Routes job configuration files +export ROUTES_CONF_DIR=${JOB_DIR}/config + +# Directory to store the Routes job log files +export ROUTES_LOG_DIR=${LOG_DIR} + +# Directory to store the Routes job process IDs +export ROUTES_PID_DIR=${RUN_DIR} + +# Directory to store the Routes job data files +export ROUTES_STORE_DIR=${STORE_DIR} + +# Directory to store the Routes job temp files +export ROUTES_TMP_DIR=${TMP_DIR} diff --git a/jobs/routes/templates/bin/routes_ctl.erb b/jobs/routes/templates/bin/routes_ctl.erb new file mode 100644 index 0000000..4df655f --- /dev/null +++ b/jobs/routes/templates/bin/routes_ctl.erb @@ -0,0 +1,85 @@ +#!/bin/bash + +set -e # exit immediately if a simple command exits with a non-zero status + +# Setup common env vars and folders +source /var/vcap/packages/bosh-helpers/ctl_setup.sh 'routes' + +list_routes() { + echo "*** $(date) Current routes:" + /sbin/route --verbose --numeric +} + +update_routes() { + list_routes + + echo "*** $(date) ${1} route:" + set +e + /sbin/route --verbose ${1} ${2} + set -e + + list_routes +} + +case $1 in + + start) + echo "****** $(date) ${0} start" + + <% p('networking.routes', []).each do |route| + route_command = "" + route_command += " -net #{route['net']}" if route['net'] + route_command += " -host #{route['host']}" if route['host'] + route_command += " netmask #{route['netmask']}" if route['netmask'] + route_command += " gw #{route['gateway']}" if route['gateway'] + route_command += " metric #{route['metric']}" if route['metric'] + route_command += " mss #{route['mss']}" if route['mss'] + route_command += " window #{route['window']}" if route['window'] + route_command += " irtt #{route['irtt']}" if route['irtt'] + route_command += " dev #{route['interface']}" if route['interface'] + %> + # Add route + update_routes add "<%= route_command %>" + <% end %> + + # Create check file + touch ${ROUTES_PID_DIR}/routes.check + ;; + + stop) + echo "****** $(date) ${0} stop" + + <% p('networking.routes', []).each do |route| + route_command = "" + route_command += " -net #{route['net']}" if route['net'] + route_command += " -host #{route['host']}" if route['host'] + route_command += " netmask #{route['netmask']}" if route['netmask'] + route_command += " gw #{route['gateway']}" if route['gateway'] + route_command += " metric #{route['metric']}" if route['metric'] + route_command += " mss #{route['mss']}" if route['mss'] + route_command += " window #{route['window']}" if route['window'] + route_command += " irtt #{route['irtt']}" if route['irtt'] + route_command += " dev #{route['interface']}" if route['interface'] + %> + # Delete route + update_routes del "<%= route_command %>" + <% end %> + + # Remove check file + rm ${ROUTES_PID_DIR}/routes.check + ;; + + status) + echo "****** $(date) ${0} status" + + # List routes + list_routes + ;; + + *) + echo "Usage: $0 {start|stop|status}" + exit 1 + ;; + +esac +exit 0 diff --git a/packages/.gitkeep b/packages/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/packages/bosh-helpers/packaging b/packages/bosh-helpers/packaging new file mode 100755 index 0000000..cc635d2 --- /dev/null +++ b/packages/bosh-helpers/packaging @@ -0,0 +1,6 @@ +set -e # exit immediately if a simple command exits with a non-zero status +set -u # report the usage of uninitialized variables + +# Copy Bosh Helpers package +echo "Copying Bosh Helpers..." +cp -a ${BOSH_COMPILE_TARGET}/bosh-helpers/* ${BOSH_INSTALL_TARGET}/ diff --git a/packages/bosh-helpers/spec b/packages/bosh-helpers/spec new file mode 100755 index 0000000..1b712f4 --- /dev/null +++ b/packages/bosh-helpers/spec @@ -0,0 +1,5 @@ +--- +name: bosh-helpers +dependencies: {} +files: + - bosh-helpers/* diff --git a/src/.gitkeep b/src/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/bosh-helpers/ctl_setup.sh b/src/bosh-helpers/ctl_setup.sh new file mode 100755 index 0000000..0f3a560 --- /dev/null +++ b/src/bosh-helpers/ctl_setup.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# Setup env vars and folders for the ctl script +# This helps keep the ctl script as readable as possible + +# Usage options: +# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh JOB_NAME OUTPUT_LABEL +# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar +# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar foobar +# source /var/vcap/jobs/foobar/helpers/ctl_setup.sh foobar nginx + +set -e # exit immediately if a simple command exits with a non-zero status + +export JOB_NAME=$1 +export OUTPUT_LABEL=${2:-$JOB_NAME} + +# Setup job home folder +export HOME=/var/vcap +export JOB_DIR=$HOME/jobs/$JOB_NAME + +# Setup log, run, store and tmp folders +export LOG_DIR=$HOME/sys/log/$JOB_NAME +export RUN_DIR=$HOME/sys/run/$JOB_NAME +export STORE_DIR=$HOME/store/$JOB_NAME +export TMP_DIR=$HOME/sys/tmp/$JOB_NAME +export TMPDIR=$TMP_DIR +for dir in $LOG_DIR $RUN_DIR $STORE_DIR $TMP_DIR +do + mkdir -p ${dir} + chown vcap:vcap ${dir} + chmod 775 ${dir} +done + +# Add all packages /bin & /sbin into $PATH +for package_bin_dir in $(ls -d $HOME/packages/*/*bin) +do + export PATH=${package_bin_dir}:$PATH +done + +# Add all packages /lib into $LD_LIBRARY_PATH +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-''} +for package_library_dir in $(ls -d $HOME/packages/*/lib) +do + export LD_LIBRARY_PATH=${package_library}:$LD_LIBRARY_PATH +done + +# Setup Java home and add it into $PATH +if [ -d $HOME/packages/java/jdk ]; then + export JAVA_HOME="$HOME/packages/java/jdk" + export PATH=$JAVA_HOME/bin:$PATH +fi + +# setup CLASSPATH for all jars/ folders within packages +export CLASSPATH=${CLASSPATH:-''} +for package_jar_dir in $(ls -d /var/vcap/packages/*/*/*.jar) +do + export CLASSPATH=${package_jar_dir}:$CLASSPATH +done + +# Load job properties +if [ -f $JOB_DIR/bin/job_properties.sh ]; then + source $JOB_DIR/bin/job_properties.sh +fi + +# Load some control helpers +source $HOME/packages/bosh-helpers/ctl_utils.sh + +# Redirect output +redirect_output ${OUTPUT_LABEL} diff --git a/src/bosh-helpers/ctl_utils.sh b/src/bosh-helpers/ctl_utils.sh new file mode 100755 index 0000000..350570b --- /dev/null +++ b/src/bosh-helpers/ctl_utils.sh @@ -0,0 +1,205 @@ +#!/usr/bin/env bash + +## +# Helper functions used by control scripts +# + +## +# Creates a user grouo +# +# Example usage: +# create_group group_name +# create_group vcap +create_group() { + group_name=$1 + getent group $group_name &>/dev/null || groupadd $group_name +} + +## +# Creates a user +# +# Example usage: +# create_user user_name group_name +# create_user vcap vcap +create_user() { + user_name=$1 + group_name=$2 + id $user_name &>/dev/null || useradd -s /sbin/nologin -r -M $user_name -G $group_name +} + +## +# Links a job file into a package +# +# Example usage: +# link_job_file_to_package config/redis.yml [config/redis.yml] +link_job_file_to_package() { + source_job_file=$1 + target_package_file=${2:-$source_job_file} + full_package_file=$WEBAPP_DIR/${target_package_file} + + link_job_file ${source_job_file} ${full_package_file} +} + +## +# Links a job file somewhere +# +# Example usage: +# link_job_file config/bashrc /home/vcap/.bashrc +link_job_file() { + source_job_file=$1 + target_file=$2 + full_job_file=$JOB_DIR/${source_job_file} + + echo link_job_file ${full_job_file} ${target_file} + if [[ ! -f ${full_job_file} ]] + then + echo "File ${full_job_file} does not exist" + else + # Create/recreate the symlink to current job file + # If another process is using the file, it won't be + # deleted, so don't attempt to create the symlink + mkdir -p $(dirname ${target_file}) + ln -nfs ${full_job_file} ${target_file} + fi +} + +## +# Redirects output +# +# Example usage: +# redirect_output jobname +redirect_output() { + SCRIPT=$1 + mkdir -p $HOME/sys/log/monit + exec 1>> $HOME/sys/log/monit/$SCRIPT.log + exec 2>> $HOME/sys/log/monit/$SCRIPT.err.log +} + +## +# Guard for pidfiles +# +# Example usage: +# pid_guard /var/vcap/sys/run/pidfile.pid jobname +pid_guard() { + pidfile=$1 + name=$2 + + if [ -f "$pidfile" ]; then + pid=$(head -1 "$pidfile") + + if [ -n "$pid" ] && [ -e /proc/$pid ]; then + echo "$name is already running, please stop it first" + exit 1 + fi + + echo "Removing stale pidfile..." + rm $pidfile + fi +} + +wait_pid() { + pid=$1 + try_kill=$2 + timeout=${3:-0} + force=${4:-0} + countdown=$(( $timeout * 10 )) + + echo wait_pid $pid $try_kill $timeout $force $countdown + if [ -e /proc/$pid ]; then + if [ "$try_kill" = "1" ]; then + echo "Killing $pidfile: $pid " + kill $pid + fi + while [ -e /proc/$pid ]; do + sleep 0.1 + [ "$countdown" != '0' -a $(( $countdown % 10 )) = '0' ] && echo -n . + if [ $timeout -gt 0 ]; then + if [ $countdown -eq 0 ]; then + if [ "$force" = "1" ]; then + echo -ne "\nKill timed out, using kill -9 on $pid... " + kill -9 $pid + sleep 0.5 + fi + break + else + countdown=$(( $countdown - 1 )) + fi + fi + done + if [ -e /proc/$pid ]; then + echo "Timed Out" + else + echo "Stopped" + fi + else + echo "Process $pid is not running" + echo "Attempting to kill pid anyway..." + kill $pid + fi +} + +wait_pidfile() { + pidfile=$1 + try_kill=$2 + timeout=${3:-0} + force=${4:-0} + countdown=$(( $timeout * 10 )) + + if [ -f "$pidfile" ]; then + pid=$(head -1 "$pidfile") + if [ -z "$pid" ]; then + echo "Unable to get pid from $pidfile" + exit 1 + fi + + wait_pid $pid $try_kill $timeout $force + + rm -f $pidfile + else + echo "Pidfile $pidfile doesn't exist" + fi +} + +kill_and_wait() { + pidfile=$1 + # Monit default timeout for start/stop is 30s + # Append 'with timeout {n} seconds' to monit start/stop program configs + timeout=${2:-25} + force=${3:-1} + if [[ -f ${pidfile} ]] + then + wait_pidfile $pidfile 1 $timeout $force + else + # TODO assume $1 is something to grep from 'ps ax' + pid="$(ps auwwx | grep "$1" | awk '{print $2}')" + wait_pid $pid 1 $timeout $force + fi +} + +check_nfs_mount() { + opts=$1 + exports=$2 + mount_point=$3 + + if grep -qs $mount_point /proc/mounts; then + echo "Found NFS mount $mount_point" + else + echo "Mounting NFS..." + mount $opts $exports $mount_point + if [ $? != 0 ]; then + echo "Cannot mount NFS from $exports to $mount_point, exiting..." + exit 1 + fi + fi +} + +public_hostname() { + public_hostname="" + + # AWS EC2 + if ec2_hostname="$( curl -sSf --connect-timeout 1 http://169.254.169.254/latest/meta-data/public-hostname 2> /dev/null)"; then + public_hostname=$ec2_hostname + fi + + echo $public_hostname +} diff --git a/src/bosh-helpers/monit_debugger b/src/bosh-helpers/monit_debugger new file mode 100755 index 0000000..7004cc3 --- /dev/null +++ b/src/bosh-helpers/monit_debugger @@ -0,0 +1,15 @@ +#!/bin/bash + +# USAGE monit_debugger