UNPKG

redbird

Version:

A reverse proxy with support for dynamic tables

136 lines (135 loc) 5.69 kB
/*eslint-env node */ 'use strict'; /** Redbird Docker Module. This module handles automatic regitration and de-registration of services running on docker containers. */ export class DockerModule { constructor(redbird, url) { this.redbird = redbird; const Dolphin = require('dolphin'); this.redbird = redbird; this.log = redbird.logger; const targets = (this.targets = {}); this.ports = {}; // We keep an up-to-date table with all the images having // containers running on the system. const images = (this.images = {}); const dolphin = (this.dolphin = new Dolphin(url)); const _this = this; // Start docker event listener this.events = dolphin.events(); this.events.on('connected', () => { // Fetch all running containers and register them if // necessary. dolphin.containers({ filters: { status: ['running'] } }).then((containers) => { for (var i = 0; i < containers.length; i++) { const container = containers[i]; this.registerIfNeeded(container.Image, container.Id, container.Names[0].replace('/', '')); } }); }); this.events.on('event', (evt) => { var _a, _b; let image; let target; (_a = this.log) === null || _a === void 0 ? void 0 : _a.info('Container %s changed to status %s', evt.Actor.Attributes.name, evt.status); switch (evt.status) { case 'start': case 'restart': case 'unpause': this.registerIfNeeded(evt.from, evt.id, evt.Actor.Attributes.name); break; case 'stop': case 'die': case 'pause': image = images[evt.from]; if (image) { for (var targetName in targets) { var match = isMatchingImageName(targetName, evt.from); if (image[evt.id] === 'running' && match && _this.ports[evt.id]) { target = targets[targetName]; (_b = this.log) === null || _b === void 0 ? void 0 : _b.info('Un-registering container %s for target %s', evt.Actor.Attributes.name, target.src); _this.redbird.unregister(target.src, _this.ports[evt.id]); } image[evt.id] = 'stopped'; } } break; default: // Nothing } }); this.events.on('error', (err) => { this.log.error(err, 'dolphin docker event error'); }); } registerIfNeeded(imageName, containerId, containerName) { var _a; const image = (this.images[imageName] = this.images[imageName] || {}); for (var targetName in this.targets) { const match = isMatchingImageName(targetName, imageName); if (match && image[containerId] !== 'running') { const target = this.targets[targetName]; (_a = this.log) === null || _a === void 0 ? void 0 : _a.info('Registering container %s for target %s', containerName, target.src); this.registerContainer(target.src, containerId, target.opts); } } image[containerId] = 'running'; } /** * Register route from a source to a given target. * The target should be an image name. Starting several containers * from the same image will automatically deliver the requests * to each container in a round-robin fashion. * * @param src See {@link ReverseProxy.register} * @param target Docker image (this string is evaluated as regexExp) * @param opts Options like ssl and etc... */ register(src, target, opts) { var storedTarget = this.targets[target]; if (storedTarget && storedTarget.src == src) { throw Error('Cannot register the same src and target twice'); } this.targets[target] = { src, opts, }; for (var imageName in this.images) { const image = this.images[imageName]; for (var containerId in image) { this.registerIfNeeded(imageName, containerId, containerId); } } } async registerContainer(src, containerId, opts) { const targetPort = await containerPort(this.dolphin, containerId); this.redbird.register(src, targetPort, opts); this.ports[containerId] = targetPort; } } function isMatchingImageName(targetName, imageName) { var regex = new RegExp('^' + targetName + '$'); return regex.test(imageName); } function containerPort(dolphin, containerId) { return dolphin.containers .inspect(containerId) .then((container) => { const port = Object.keys(container.NetworkSettings.Ports)[0].split('/')[0]; const netNames = Object.keys(container.NetworkSettings.Networks); if (netNames.length === 1) { const ip = container.NetworkSettings.Networks[netNames[0]].IPAddress; if (port && ip) { return 'http://' + ip + ':' + port; } } else { //TODO: Implements opts for manually choosing the network/ip/port... } throw Error('No valid address or port ' + container.IPAddress + ':' + port); }); } //# sourceMappingURL=docker.js.map