swarmerode
Advanced tools
Comparing version 0.1.0 to 0.2.0
89
index.js
'use strict' | ||
var clone = require('101/clone') | ||
var exists = require('101/exists') | ||
var pluck = require('101/pluck') | ||
@@ -19,8 +19,9 @@ /* | ||
Swarmerode.prototype.swarmHosts = function (cb) { | ||
var ipRegex = new RegExp('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5}$') | ||
this.info(function (err, data) { | ||
this.swarmInfo(function (err, data) { | ||
if (err) { return cb(err) } | ||
var hosts = data.DriverStatus | ||
.map(pluck(1)) | ||
.filter(ipRegex.test.bind(ipRegex)) | ||
var nodes = data.parsedSystemStatus.ParsedNodes | ||
var hosts = Object.keys(nodes) | ||
.map(function (key) { | ||
return nodes[key].Host | ||
}) | ||
cb(null, hosts) | ||
@@ -31,2 +32,14 @@ }) | ||
/** | ||
* Return a formated list of swarm nodes | ||
* @param {Function} cb Callback with signature (err, nodes). | ||
*/ | ||
Swarmerode.prototype.swarmInfo = function (cb) { | ||
this.info(function (err, info) { | ||
if (err) { return cb(err) } | ||
info.parsedSystemStatus = Swarmerode._parseSwarmSystemStatus(info.SystemStatus) | ||
cb(null, info) | ||
}) | ||
} | ||
/** | ||
* Return a boolean indicating if a swarm host exists. | ||
@@ -45,2 +58,66 @@ * @param {String} host Host address (e.g. `10.0.0.1:2375`). | ||
/** | ||
* Parse and transform raw swarm data into the proper JSON. | ||
* format: { | ||
* Role: 'primary' | ||
* Strategy: 'spread' | ||
* Filters: 'health, port, dependency, affinity, constraint' | ||
* Nodes: 42 | ||
* ParsedNodes: { | ||
* <nodeHostname>: { | ||
* Host: '10.0.0.1:4242, | ||
* Containers: 5, | ||
* ReservedCpus: '0 / 1', | ||
* ReservedMem: '10 GiB / 1.021 GiB', | ||
* Labels: { | ||
* env: 'prod', | ||
* provider: 'virtualbox' | ||
* }, | ||
* Error: '(none)', | ||
* UpdatedAt: '2016-03-08T19:02:41Z' | ||
* } | ||
* } | ||
* } | ||
* @param {Array} - array data response from swarm info | ||
* @return array of json objects with swarm data for each node | ||
*/ | ||
Swarmerode._parseSwarmSystemStatus = function (systemStatus) { | ||
systemStatus = clone(systemStatus) | ||
// the first 4 fields are Role, Strategy, Filters, Nodes respectively | ||
var formatted = { | ||
Role: systemStatus.shift()[1], | ||
Strategy: systemStatus.shift()[1], | ||
Filters: systemStatus.shift()[1], | ||
Nodes: parseInt(systemStatus.shift()[1], 10), | ||
ParsedNodes: {} | ||
} | ||
for (var i = 0; i < formatted.Nodes; i++) { | ||
formatted.ParsedNodes[systemStatus[0][0].trim()] = { | ||
Host: systemStatus.shift()[1], | ||
Status: systemStatus.shift()[1], | ||
Containers: parseInt(systemStatus.shift()[1], 10), | ||
ReservedCpus: systemStatus.shift()[1], | ||
ReservedMem: systemStatus.shift()[1], | ||
Labels: parseLabels(systemStatus.shift()[1]), | ||
Error: systemStatus.shift()[1], | ||
UpdatedAt: systemStatus.shift()[1] | ||
} | ||
} | ||
function parseLabels (labelString) { | ||
var labelsTokens = labelString.split(',') | ||
var labels = {} | ||
labelsTokens.forEach(function (labelToken) { | ||
var pair = labelToken.split('=').map(function (s) { | ||
return s.trim() | ||
}) | ||
labels[pair[0]] = pair[1] | ||
}) | ||
return labels | ||
} | ||
return formatted | ||
} | ||
/** | ||
* Extend a given Class's prototype with the swarm functions. | ||
@@ -47,0 +124,0 @@ * @param {Function} Class A 'Class' of which to extend the prototype |
{ | ||
"name": "swarmerode", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Swarm Client Extension for Dockerode", | ||
@@ -44,2 +44,3 @@ "main": "index.js", | ||
"coveralls": "^2.11.6", | ||
"github-changes": "^1.0.1", | ||
"istanbul": "^0.4.2", | ||
@@ -46,0 +47,0 @@ "mocha": "^2.3.4", |
@@ -5,3 +5,3 @@ 'use strict' | ||
function hostEntry (host) { | ||
function hostEntry (hostInfo) { | ||
var hostIndex = index++ | ||
@@ -16,8 +16,18 @@ var labelString = [ | ||
].join(', ') | ||
if (hostInfo.Labels) { | ||
labelString += ', ' + hostInfo.Labels | ||
} | ||
var nodeName = hostInfo.nodeName || (' swarm-agent-0' + hostIndex) | ||
var host = hostInfo.host || ('10.0.0.' + hostIndex + ':4242') | ||
var numContainers = hostInfo.Containers || '1' | ||
return [ | ||
[ 'swarm-agent-0' + hostIndex, host ], | ||
[ ' └ Containers', '12' ], | ||
[ ' └ Reserved CPUs', '0 / 1' ], | ||
[ ' └ Reserved Memory', '10 GiB / 1.021 GiB' ], | ||
[ ' └ Labels', labelString ] | ||
[ nodeName, host ], | ||
[ ' └ Status', 'Healthy' ], | ||
[ ' └ Containers', numContainers ], | ||
[ ' └ Reserved CPUs', '0 / 1' ], | ||
[ ' └ Reserved Memory', '10 GiB / 1.021 GiB' ], | ||
[ ' └ Labels', labelString ], | ||
[ ' └ Error', '(none)' ], | ||
[ ' └ UpdatedAt', '2016-03-08T19:02:41Z' ] | ||
] | ||
@@ -30,42 +40,59 @@ } | ||
} | ||
var driverStatus = [ | ||
[ '\bRole', 'primary' ], | ||
[ '\bStrategy', 'spread' ], | ||
[ '\bFilters', 'health, port, dependency, affinity, constraint' ], | ||
[ '\bNodes', testHosts.length.toString() ] | ||
var SystemStatus = [ | ||
[ 'Role', 'primary' ], | ||
[ 'Strategy', 'spread' ], | ||
[ 'Filters', 'health, port, dependency, affinity, constraint' ], | ||
[ 'Nodes', testHosts.length.toString() ] | ||
] | ||
testHosts.forEach(function (host) { | ||
driverStatus.push.apply(driverStatus, hostEntry(host)) | ||
testHosts.forEach(function (hostInfo) { | ||
SystemStatus.push.apply(SystemStatus, hostEntry(hostInfo)) | ||
}) | ||
return { | ||
ServerVersion: 'swarm/1.1.2', | ||
ID: '', | ||
Containers: 16, | ||
Containers: 25, | ||
ContainersRunning: 5, | ||
ContainersPaused: 0, | ||
ContainersStopped: 20, | ||
Images: 46, | ||
Driver: '', | ||
DriverStatus: driverStatus, | ||
ExecutionDriver: '', | ||
Images: 7, | ||
KernelVersion: '', | ||
OperatingSystem: '', | ||
NCPU: testHosts.length, | ||
MemTotal: 3290421657, | ||
Name: 'f0877b9fe8c1', | ||
Labels: null, | ||
Debug: false, | ||
NFd: 0, | ||
NGoroutines: 0, | ||
SystemTime: '2015-12-11T00:30:01.504395876Z', | ||
NEventsListener: 0, | ||
InitPath: '', | ||
InitSha1: '', | ||
IndexServerAddress: '', | ||
DriverStatus: null, | ||
Plugins: { Volume: null, Network: null, Authorization: null }, | ||
MemoryLimit: true, | ||
SwapLimit: true, | ||
CpuCfsPeriod: true, | ||
CpuCfsQuota: true, | ||
CPUShares: true, | ||
CPUSet: true, | ||
IPv4Forwarding: true, | ||
BridgeNfIptables: true, | ||
BridgeNfIp6tables: true, | ||
Debug: false, | ||
NFd: 0, | ||
OomKillDisable: true, | ||
NGoroutines: 0, | ||
SystemTime: '2016-03-08T19:02:46.450133201Z', | ||
ExecutionDriver: '', | ||
LoggingDriver: '', | ||
NEventsListener: 1, | ||
KernelVersion: '3.13.0-77-generic', | ||
OperatingSystem: 'linux', | ||
OSType: '', | ||
Architecture: 'amd64', | ||
IndexServerAddress: '', | ||
RegistryConfig: null, | ||
NCPU: 4, | ||
MemTotal: 17580879052, | ||
DockerRootDir: '', | ||
HttpProxy: '', | ||
HttpsProxy: '', | ||
NoProxy: '' | ||
NoProxy: '', | ||
Name: '005f6adac88b', | ||
Labels: null, | ||
ExperimentalBuild: false, | ||
ClusterStore: '', | ||
ClusterAdvertise: '', | ||
SystemStatus: SystemStatus | ||
} | ||
} |
'use strict' | ||
var assert = require('chai').assert | ||
var clone = require('101/clone') | ||
var sinon = require('sinon') | ||
var exampleHosts = [ '10.0.0.1:4242', '10.0.0.2:4242', '10.0.0.3:4242' ] | ||
var swarmInfoData = require('./fixtures/swarm-info')(exampleHosts) | ||
var swarmInfoMock = require('./fixtures/swarm-info') | ||
var testInfo = swarmInfoMock([{ host: exampleHosts[0] }, { host: exampleHosts[1] }, { host: exampleHosts[2] }]) | ||
var Swarmerode = require('../') | ||
@@ -15,3 +17,3 @@ | ||
MockClass = function () {} | ||
MockClass.prototype.info = function (cb) { cb(null, swarmInfoData) } | ||
MockClass.prototype.info = function (cb) { cb(null, clone(testInfo)) } | ||
MockClass = Swarmerode(MockClass) | ||
@@ -121,2 +123,50 @@ instance = new MockClass() | ||
}) | ||
describe('_parseSwarmSystemStatus', function () { | ||
it('should format SystemStatus correctly', function (done) { | ||
var coolNode = { | ||
Labels: 'env=test, hd=ssd', | ||
Containers: 100, | ||
nodeName: ' cool.node', | ||
host: '10.42.42.42:4242' | ||
} | ||
var uncoolNode = { | ||
Labels: 'env=prod, hd=disk', | ||
Containers: 4, | ||
nodeName: ' un.cool.node', | ||
host: '10.7.7.7:4242' | ||
} | ||
var testHosts = swarmInfoMock([coolNode, uncoolNode]) | ||
var out = Swarmerode._Swarmerode._parseSwarmSystemStatus(testHosts.SystemStatus) | ||
assert.equal(out.Role, 'primary') | ||
assert.equal(out.Strategy, 'spread') | ||
assert.equal(out.Filters, 'health, port, dependency, affinity, constraint') | ||
assert.isNumber(out.Nodes) | ||
assert.equal(out.Nodes, 2) | ||
assert.equal(out.ParsedNodes['cool.node'].Host, coolNode.host) | ||
assert.isNumber(out.ParsedNodes['cool.node'].Containers) | ||
assert.equal(out.ParsedNodes['cool.node'].Containers, 100) | ||
assert.equal(out.ParsedNodes['cool.node'].Status, 'Healthy') | ||
assert.equal(out.ParsedNodes['cool.node'].ReservedCpus, '0 / 1') | ||
assert.equal(out.ParsedNodes['cool.node'].ReservedMem, '10 GiB / 1.021 GiB') | ||
assert.equal(out.ParsedNodes['cool.node'].Error, '(none)') | ||
assert.equal(out.ParsedNodes['cool.node'].UpdatedAt, '2016-03-08T19:02:41Z') | ||
assert.equal(out.ParsedNodes['cool.node'].Labels.env, 'test') | ||
assert.equal(out.ParsedNodes['cool.node'].Labels.hd, 'ssd') | ||
assert.equal(out.ParsedNodes['un.cool.node'].Host, uncoolNode.host) | ||
assert.isNumber(out.ParsedNodes['un.cool.node'].Containers) | ||
assert.equal(out.ParsedNodes['un.cool.node'].Status, 'Healthy') | ||
assert.equal(out.ParsedNodes['un.cool.node'].Containers, 4) | ||
assert.equal(out.ParsedNodes['un.cool.node'].ReservedCpus, '0 / 1') | ||
assert.equal(out.ParsedNodes['un.cool.node'].ReservedMem, '10 GiB / 1.021 GiB') | ||
assert.equal(out.ParsedNodes['un.cool.node'].Error, '(none)') | ||
assert.equal(out.ParsedNodes['un.cool.node'].UpdatedAt, '2016-03-08T19:02:41Z') | ||
assert.equal(out.ParsedNodes['un.cool.node'].Labels.env, 'prod') | ||
assert.equal(out.ParsedNodes['un.cool.node'].Labels.hd, 'disk') | ||
done() | ||
}) | ||
}) // end _parseSwarmSystemStatus | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15838
365
7
1