From dcb413b32dd312dd9e06eb9c92994f81407a01c9 Mon Sep 17 00:00:00 2001 From: Silas Sewell Date: Sat, 5 Sep 2015 13:53:36 -0400 Subject: [PATCH] Support multiple checks in agent.service.register Fixes #15 --- README.md | 6 ++++-- lib/agent/check.js | 23 ++++------------------- lib/agent/service.js | 26 +++++++------------------- lib/kv.js | 2 +- lib/utils.js | 34 +++++++++++++++++++++++++++++++++- test/agent.js | 28 ++++++++++++++++++++++++++++ test/utils.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 119 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index bd90ae7..ffde680 100644 --- a/README.md +++ b/README.md @@ -488,7 +488,7 @@ Options * serviceid (String, optional): service ID, associate check with existing service * http (String): url to test, 2xx passes, 429 warns, and all others fail * script (String): path to check script, requires interval - * internal (String): interval to run check, requires script (ex: `15s`) + * interval (String): interval to run check, requires script (ex: `15s`) * ttl (String): time to live before check must be updated, instead of script and interval (ex: `60s`) * notes (String, optional): human readable description of check * status (String, optional): initial service status @@ -626,11 +626,13 @@ Options * id (String, optional): service ID * tags (String[], optional): service tags * check (Object, optional): service check + * http (String): URL endpoint, requires interval * script (String): path to check script, requires interval * internal (String): interval to run check, requires script (ex: `15s`) - * ttl (String): time to live before check must be updated, instead of script and interval (ex: `60s`) + * ttl (String): time to live before check must be updated, instead of http/script and interval (ex: `60s`) * notes (String, optional): human readable description of check * status (String, optional): initial service status + * checks (Object[], optional): service checks (see `check` above) Usage diff --git a/lib/agent/check.js b/lib/agent/check.js index beaa713..c75d9f1 100644 --- a/lib/agent/check.js +++ b/lib/agent/check.js @@ -54,32 +54,17 @@ AgentCheck.prototype.register = function(opts, callback) { name: 'agent.check.register', path: '/agent/check/register', type: 'json', - body: {}, }; if (!opts.name) { return callback(this.consul._err(errors.Validation('name required'), req)); } - req.body.Name = opts.name; - - if (opts.serviceid) req.body.ServiceID = opts.serviceid; - if (opts.hasOwnProperty('id')) req.body.ID = opts.id; - if ((opts.http || opts.script) && opts.interval) { - if (opts.http) { - req.body.HTTP = opts.http; - } else { - req.body.Script = opts.script; - } - req.body.Interval = opts.interval; - } else if (opts.ttl) { - req.body.TTL = opts.ttl; - } else { - return callback(this.consul._err( - errors.Validation('http or script and interval, or ttl required'), req)); + try { + req.body = utils.createCheck(opts); + } catch (err) { + return callback(this.consul._err(errors.Validation(err.message), req)); } - if (opts.hasOwnProperty('notes')) req.body.Notes = opts.notes; - if (opts.hasOwnProperty('status')) req.body.Status = opts.status; utils.options(req, opts); diff --git a/lib/agent/service.js b/lib/agent/service.js index 0083692..79106f8 100644 --- a/lib/agent/service.js +++ b/lib/agent/service.js @@ -71,26 +71,14 @@ AgentService.prototype.register = function(opts, callback) { if (opts.hasOwnProperty('address')) req.body.Address = opts.address; if (opts.hasOwnProperty('port')) req.body.Port = opts.port; - if (opts.check) { - var check = utils.normalizeKeys(opts.check); - - req.body.Check = {}; - - if ((check.http || check.script) && check.interval) { - if (check.http) { - req.body.Check.HTTP = check.http; - } else { - req.body.Check.Script = check.script; - } - req.body.Check.Interval = check.interval; - } else if (check.ttl) { - req.body.Check.TTL = check.ttl; - } else { - return callback(this.consul._err( - errors.Validation('http or script and interval, or ttl required'), req)); + try { + if (Array.isArray(opts.checks)) { + req.body.Checks = opts.checks.map(utils.createCheck); + } else if (opts.check) { + req.body.Check = utils.createCheck(opts.check); } - if (check.hasOwnProperty('notes')) req.body.Check.Notes = check.notes; - if (check.hasOwnProperty('status')) req.body.Check.Status = check.status; + } catch (err) { + return callback(this.consul._err(errors.Validation(err.message), req)); } utils.options(req, opts); diff --git a/lib/kv.js b/lib/kv.js index 22e8c7a..2df7d7a 100644 --- a/lib/kv.js +++ b/lib/kv.js @@ -178,7 +178,7 @@ Kv.prototype.del = function(opts, callback) { this.consul._delete(req, utils.empty, callback); }; -Kv.prototype['delete'] = Kv.prototype.del; +Kv.prototype.delete = Kv.prototype.del; /** * Module exports. diff --git a/lib/utils.js b/lib/utils.js index ad4be39..fce9b3f 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -51,7 +51,7 @@ function empty(request, next) { function normalizeKeys(obj) { var result = {}; - if (obj) { + if (obj && !obj._normalizeKeys) { for (var name in obj) { if (obj.hasOwnProperty(name)) { result[name.replace(/_/g, '').toLowerCase()] = obj[name]; @@ -197,6 +197,37 @@ function setIntervalContext(fn, ctx, timeout) { ctx.once('cancel', cancel); } +/** + * Create check object + */ + +function createCheck(src) { + src = normalizeKeys(src); + + var dst = {}; + + if (src.hasOwnProperty('id')) dst.ID = src.id; + if (src.hasOwnProperty('name')) dst.Name = src.name; + if (src.hasOwnProperty('serviceid')) dst.ServiceID = src.serviceid; + + if ((src.http || src.script) && src.interval) { + if (src.http) { + dst.HTTP = src.http; + } else { + dst.Script = src.script; + } + dst.Interval = src.interval; + } else if (src.ttl) { + dst.TTL = src.ttl; + } else { + throw new Error('http or script and interval, or ttl required'); + } + if (src.hasOwnProperty('notes')) dst.Notes = src.notes; + if (src.hasOwnProperty('status')) dst.Status = src.status; + + return dst; +} + /** * Module exports */ @@ -212,3 +243,4 @@ exports.clone = clone; exports.parseDuration = parseDuration; exports.setTimeoutContext = setTimeoutContext; exports.setIntervalContext = setIntervalContext; +exports.createCheck = createCheck; diff --git a/test/agent.js b/test/agent.js index ecbb3a9..cadd1e5 100644 --- a/test/agent.js +++ b/test/agent.js @@ -494,6 +494,34 @@ describe('Agent', function() { }); }); + it('should work with multiple checks', function(done) { + this.nock + .put('/v1/agent/service/register', { + ID: '123', + Name: 'service', + Checks: [ + { TTL: '10s' }, + { HTTP: 'http://127.0.0.1:8000', Interval: '60s' }, + ], + }) + .reply(200); + + var opts = { + id: '123', + name: 'service', + checks: [ + { ttl: '10s' }, + { http: 'http://127.0.0.1:8000', interval: '60s' }, + ], + }; + + this.consul.agent.service.register(opts, function(err) { + should.not.exist(err); + + done(); + }); + }); + it('should work with only name', function(done) { this.nock .put('/v1/agent/service/register', { Name: 'service' }) diff --git a/test/utils.js b/test/utils.js index b031723..cf5927b 100644 --- a/test/utils.js +++ b/test/utils.js @@ -262,4 +262,46 @@ describe('utils', function() { self.ctx.emit('cancel'); }); }); + + describe('createCheck', function() { + it('should work', function() { + should(utils.createCheck({ + ID: 'id', + name: 'name', + service_id: 'service', + http: 'http://127.0.0.1:8000', + interval: '60s', + notes: 'Just a note.', + status: 'passing', + })).eql({ + ID: 'id', + Name: 'name', + ServiceID: 'service', + HTTP: 'http://127.0.0.1:8000', + Interval: '60s', + Notes: 'Just a note.', + Status: 'passing', + }); + + should(utils.createCheck({ + script: '/usr/bin/true', + interval: '30s', + })).eql({ + Script: '/usr/bin/true', + Interval: '30s', + }); + + should(utils.createCheck({ + ttl: '15s', + })).eql({ + TTL: '15s', + }); + }); + + it('should require script, http, or ttl', function() { + should(function() { + utils.createCheck(); + }).throw('http or script and interval, or ttl required'); + }); + }); });