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/src/Dockerfile b/src/Dockerfile new file mode 100644 index 0000000..7fa8971 --- /dev/null +++ b/src/Dockerfile @@ -0,0 +1,9 @@ +FROM node + +COPY . /src + +WORKDIR /src +RUN npm config set loglevel win +RUN npm install + +CMD ["node", "program"] \ No newline at end of file diff --git a/src/consulWriter.js b/src/consulWriter.js new file mode 100644 index 0000000..c2f4661 --- /dev/null +++ b/src/consulWriter.js @@ -0,0 +1,47 @@ +// Set module exports +module.exports = { + registerServices: registerServices, + deregisterServices: deregisterServices +}; + +// Registers the specified services in consul (will auto-deregister first) +function registerServices(consulHost, consulPort, services) { + // Get consul + var consul = require('consul')({ host: consulHost, port: consulPort }); + + // Enumerate the services + services.forEach(function (service) { + // Deregister the service by id, just in case + consul.agent.service.deregister({ id: service.id }, function (err) { + // Handle error + if (err) throw err; + + // Register the service + consul.agent.service.register({ + name: service.name, + id: service.id, + address: service.address, + port: service.port, + tags: ['auto-registered'], + }, function (err) { + // Handle error + if (err) throw err; + }); + }); + }); +} + +// Deregisters the specified services in consul +function deregisterServices(consulHost, consulPort, services) { + // Get consul + var consul = require('consul')({ host: consulHost, port: consulPort }); + + // Enumerate the services + services.forEach(function (service) { + // Deregister the service by id, just in case + consul.agent.service.deregister({ id: service.id }, function (err) { + // Handle error + if (err) throw err; + }); + }); +} \ No newline at end of file diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..7bfa405 --- /dev/null +++ b/src/package.json @@ -0,0 +1,20 @@ +{ + "name": "tutum-registrator", + "version": "1.0.0", + "description": "Registers containers in tutum to consul", + "main": "program.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "request": "^2.67.0", + "consul": "^0.20.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/chaseajen/tutum-registrator.git" + }, + + "author": "Chase Jenkins", + "license": "ISC" +} diff --git a/src/program.js b/src/program.js new file mode 100644 index 0000000..30e4f7c --- /dev/null +++ b/src/program.js @@ -0,0 +1,42 @@ +var request = require('request'); +var tutumReader = require('./tutumReader'); +var consulWriter = require('./consulWriter'); + +var containerApiUrl = "https://dashboard.tutum.co/api/v1/container"; + +// Check args +var args = process.argv; +if (args.length < 6) { + console.error("Insufficient arguments. Usage: node program tutum_user tutum_api_token consul_host consul_port"); + process.exit(1); +} + +// Read args +var user = args[2]; +var token = args[3]; +var consulHost = args[4]; +var consulPort = args[5]; + +// Start processing +console.info("starting tutum-registrator. Tutum info: (%s, %s). Consul info: (%s:%d)", user, token, consulHost, consulPort); +setInterval(run, 10000); + +function run() { + // Read stopped containers and deregister + tutumReader.readContainers(containerApiUrl + "?state=Stopped&limit=1000", user, token, function (err, data) { + if (err) return console.error("failed to read stopped containers: " + err); + consulWriter.deregisterServices(consulHost, consulPort, data); + }); + + // Read stopped containers and deregister + tutumReader.readContainers(containerApiUrl + "?state=Terminated&limit=1000", user, token, function (err, data) { + if (err) return console.error("failed to read stopped containers: " + err); + consulWriter.deregisterServices(consulHost, consulPort, data); + }); + + // Read running containers and register + tutumReader.readContainers(containerApiUrl + "?state=Running&limit=1000", user, token, function (err, data) { + if (err) return console.error("failed to read running containers: " + err); + consulWriter.registerServices(consulHost, consulPort, data); + }); +} diff --git a/src/tutumReader.js b/src/tutumReader.js new file mode 100644 index 0000000..4109c96 --- /dev/null +++ b/src/tutumReader.js @@ -0,0 +1,73 @@ +// Set module exports +module.exports = { + readContainers: readContainers +}; + +// Requires +var request = require('request'); + +// Reads the containers from the API +function readContainers(url, user, token, callback) { + request.get(url, { auth: { user: user, pass: token, sendImmediately: false } }, function (err, response, body) { + // Handle response + if (err) callback(err, null); + if (response.statusCode != 200) callback(response.statusCode, null); + + // Process the body + processResponseBody(body, callback); + }); +} + + // Process the raw response from the tutum container API and create service objects from it +function processResponseBody(body, callback) { + // Parse as JSON + var data = JSON.parse(body); + + // Enumerate and generate services + var results = []; + for (var i = 0; i < data.objects.length; i++) { + var container = data.objects[i]; + + var containerName = container.name; + var tutumServiceName = containerName.split('-')[0]; + + // Get both the private IP and the public DNS + var privateIp = container.private_ip; + var publicDns = container.public_dns; + + // Enumerate the ports + var ports = container.container_ports; + for (var portIndex = 0; portIndex < ports.length; portIndex++) { + var port = ports[portIndex]; + + var published = port.published; + var innerPort = port.inner_port; + var outerPort = port.outer_port; + + var serviceName = tutumServiceName + "-" + innerPort; + + // Create the service object + var service = { + id: containerName + "-" + serviceName, + name: serviceName, + container: containerName, + published: published + }; + + // Assign the address and port dependent on whether it's published + if (published) { + service.address = publicDns; + service.port = outerPort; + } + else { + service.address = privateIp; + service.port = innerPort; + } + + // Add the service to the results + results.push(service); + } + } + + callback(null, results); +} \ No newline at end of file