From 17acb5582eb1075e9823695e52b4d17ab1a81caf Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Mon, 27 Jan 2020 17:25:39 +0100 Subject: [PATCH] Initial commit --- .gitignore | 1 + Dockerfile | 24 +++ LICENSE | 17 ++ README.md | 10 ++ config.json | 18 +++ docker-compose.yml | 29 ++++ index.js | 77 +++++++++ package-lock.json | 396 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 15 ++ rproxy.handlebars | 11 ++ test.json | 33 ++++ 11 files changed, 631 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 config.json create mode 100644 docker-compose.yml create mode 100644 index.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 rproxy.handlebars create mode 100644 test.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..85e75af --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM debian:buster-slim + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + gnupg2 \ + libfontconfig \ + && curl -sL https://deb.nodesource.com/setup_10.x | bash - \ + && apt-get install -y --no-install-recommends \ + nodejs \ + && apt-get purge -y --auto-remove \ + gnupg2 \ + && rm -rf /var/lib/apt/lists/* \ + && npm -g install pm2 + +WORKDIR /docker-discover +COPY package.json package-lock.json ./ +RUN npm install --only=prod + +COPY index.js config.json rproxy.handlebars ./ + +CMD ["pm2-runtime", "index.js"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3536903 --- /dev/null +++ b/LICENSE @@ -0,0 +1,17 @@ + Copyright (C) 2020 - Verdnatura Levante S.L. + + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + On Debian systems, the complete text of the GNU General Public + License can be found in "/usr/share/common-licenses/GPL-3". \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9a87c2c --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Docker service autodicovery + +Small Javascript application to generate HAProxy configuration from Docker +services. + +## Built with + + * [dockerode](https://github.com/apocas/dockerode/) + * [handlebars](https://handlebarsjs.com/) + \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..8220550 --- /dev/null +++ b/config.json @@ -0,0 +1,18 @@ +{ + "docker": { + "socketPath": "/var/run/docker.sock" + }, + "rproxies": [ + "rproxy1.local", + "rproxy2.local" + ], + "sshAuth": { + "username": "root", + "privateKey": "/root/.ssh/id_rsa" + }, + "proxyConf": "/etc/haproxy/haproxy.cfg", + "reloadCmd": "service haproxy reload", + "delay": 4, + "debug": false, + "events": ["service", "node"] +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..240c51b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: '3.7' +services: + discover: + image: registry.verdnatura.es/docker-discover + build: . + environment: + - NODE_ENV=production + volumes: + - /var/run/docker.sock:/var/run/docker.sock + configs: + - source: config + target: /docker-discover/config.json + - source: template + target: /docker-discover/rproxy.handlebars + - source: ssh + target: /root/.ssh/id_rsa + deploy: + mode: replicated + replicas: 1 +configs: + config: + external: true + name: discover_config + template: + external: true + name: discover_template + ssh: + external: true + name: discover_ssh diff --git a/index.js b/index.js new file mode 100644 index 0000000..27f8a0c --- /dev/null +++ b/index.js @@ -0,0 +1,77 @@ +let Docker = require('dockerode'); +let handlebars = require('handlebars'); +let ssh = require('node-ssh'); +let fs = require('fs'); +let conf = require('./config.json'); + +let docker; +let template; + +async function updateProxy() { + console.log('Updating proxy configuration.'); + let data; + + if (process.env.NODE_ENV != 'production') { + data = require('./test.json'); + } else { + data = { + services: await docker.listServices(), + nodes: await docker.listNodes() + }; + } + + let tmpConf = `/tmp/rproxy.${new Date().getTime()}`; + let configString = template(data); + fs.writeFileSync(tmpConf, configString); + + if (conf.debug || process.env.NODE_ENV != 'production') { + let delimiter = '#'.repeat(80); + console.log(delimiter); + console.log(configString); + console.log(delimiter); + } + + let files = { + local: tmpConf, + remote: conf.proxyConf + }; + + for (let host of conf.rproxies) { + console.log(`Updating host: ${host}`); + let sshClient = new ssh(); + await sshClient.connect(Object.assign({host}, conf.sshAuth)); + await sshClient.putFiles([files]); + //await ssh.exec(conf.reloadCmd); + await sshClient.dispose(); + } + + fs.unlinkSync(tmpConf); + console.log('Configuration updated.'); +} + +(async() => { + let timeoutId; + docker = new Docker(conf.docker); + template = handlebars.compile(fs.readFileSync('rproxy.handlebars', 'utf8')); + updateProxy(); + + console.log('Listenig for events.') + docker.getEvents({}, (err, stream) => { + if (err || !stream) { + console.error('Failed to monitor docker host', err); + return; + } + + stream.on('data', event => { + event = JSON.parse(event); + if (conf.events && conf.events.indexOf(event.Type) == -1) return; + console.log(`Event: ${event.Type}: ${event.Action}`); + + if (timeoutId) return; + timeoutId = setTimeout(() => { + timeoutId = null; + updateProxy(); + }, conf.delay * 1000); + }) + }); +})(); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6661f77 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,396 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "JSONStream": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", + "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "aggregate-error": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", + "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", + "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", + "requires": { + "readable-stream": "^3.0.1" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "optional": true + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "docker-modem": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.0.4.tgz", + "integrity": "sha512-fj0pt7iEXCPCN9wDWJRyjQJ1POcmCwPmuId/Eg+bxULsxI7l9GHEyol4HY9fH4B/I69J67ATqQ09SOfzgwbZlg==", + "requires": { + "JSONStream": "1.3.2", + "debug": "^3.2.6", + "readable-stream": "~1.0.26-4", + "split-ca": "^1.0.0", + "ssh2": "^0.8.5" + }, + "dependencies": { + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + } + } + }, + "dockerode": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.0.2.tgz", + "integrity": "sha512-jql7zwTQH2psjyevyeWOpe9XJ8x1WbXX/TwKHcWlJsq1jivxN2+1nVqT72HKE9xxNR/MGcuWcPxrCBHNu9GZpw==", + "requires": { + "concat-stream": "~2.0.0", + "docker-modem": "^2.0.0", + "tar-fs": "~2.0.0" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "handlebars": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.2.tgz", + "integrity": "sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==", + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, + "node-ssh": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-7.0.0.tgz", + "integrity": "sha512-LwdGalFACK+DCVI1+wkehR/a8uIkmAn0npW43f8U6XhH20112a/WAXv3oQay7IK2YHY1J6r5JT2MEHhjyQxKIA==", + "requires": { + "p-map": "^3.0.0", + "sb-promisify": "^2.0.1", + "sb-scandir": "^2.0.0", + "shell-escape": "^0.2.0", + "ssh2": "^0.8.7" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "readable-stream": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.5.0.tgz", + "integrity": "sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sb-promisify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sb-promisify/-/sb-promisify-2.0.2.tgz", + "integrity": "sha1-QnelR1RIiqlnXYhuNU24lMm9yYE=" + }, + "sb-scandir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sb-scandir/-/sb-scandir-2.0.0.tgz", + "integrity": "sha512-SKbyMJB0DUt9OgN4tP2RBcn9OsR26DEpe+nwaDkQTNcrJSJI0FlLhXhBpTd/YEnlQ2GdLrbszSNekGLw4rweOQ==", + "requires": { + "p-map": "^1.2.0", + "sb-promisify": "^2.0.1" + }, + "dependencies": { + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" + } + } + }, + "shell-escape": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/shell-escape/-/shell-escape-0.2.0.tgz", + "integrity": "sha1-aP0CXrBJC09WegJ/C/IkgLX4QTM=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=" + }, + "ssh2": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.7.tgz", + "integrity": "sha512-/u1BO12kb0lDVxJXejWB9pxyF3/ncgRqI9vPCZuPzo05pdNDzqUeQRavScwSPsfMGK+5H/VRqp1IierIx0Bcxw==", + "requires": { + "ssh2-streams": "~0.4.8" + } + }, + "ssh2-streams": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.8.tgz", + "integrity": "sha512-auxXfgYySz2vYw7TMU7PK7vFI7EPvhvTH8/tZPgGaWocK4p/vwCMiV3icz9AEkb0R40kOKZtFtqYIxDJyJiytw==", + "requires": { + "asn1": "~0.2.0", + "bcrypt-pbkdf": "^1.0.2", + "streamsearch": "~0.1.2" + } + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "tar-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "requires": { + "chownr": "^1.1.1", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", + "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", + "requires": { + "bl": "^3.0.0", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "uglify-js": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.6.tgz", + "integrity": "sha512-yYqjArOYSxvqeeiYH2VGjZOqq6SVmhxzaPjJC1W2F9e+bqvFL9QXQ2osQuKUFjM2hGjKG2YclQnRKWQSt/nOTQ==", + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b7efc70 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "docker-discover", + "description": "Docker service autodiscovery", + "license": "GPL-3.0", + "repository": { + "type": "git", + "url": "https://gitea.verdnatura.es/verdnatura/docker-discover" +}, + + "dependencies": { + "dockerode": "^3.0.2", + "handlebars": "^4.7.2", + "node-ssh": "^7.0.0" + } +} diff --git a/rproxy.handlebars b/rproxy.handlebars new file mode 100644 index 0000000..59a8219 --- /dev/null +++ b/rproxy.handlebars @@ -0,0 +1,11 @@ + +# Auto-generated backends + +{{#each services}} +{{#if Endpoint.Ports.[0]}} +backend {{Spec.Name}} + {{#each ../nodes}} + server {{Description.Hostname}}({{Status.Addr}}):{{../Endpoint.Ports.[0].PublishedPort}} {{Status.Addr}}:{{../Endpoint.Ports.[0].PublishedPort}} check + {{/each}} +{{/if}} +{{/each}} diff --git a/test.json b/test.json new file mode 100644 index 0000000..7129126 --- /dev/null +++ b/test.json @@ -0,0 +1,33 @@ +{ + "services": [ + { + "Spec": {"Name": "service1"}, + "Endpoint": { + "Ports": [ + {"PublishedPort": 10001} + ] + } + }, { + "Spec": {"Name": "service2"}, + "Endpoint": { + "Ports": [] + } + }, { + "Spec": {"Name": "service3"}, + "Endpoint": { + "Ports": [ + {"PublishedPort": 10003} + ] + } + } + ], + "nodes": [ + { + "Description": {"Hostname": "node1"}, + "Status": {"Addr": "10.0.0.1"} + }, { + "Description": {"Hostname": "node2"}, + "Status": {"Addr": "10.0.0.2"} + } + ] +} \ No newline at end of file