MXS-1300: Send requests to multiple hosts

The host and port options were replace with one hosts option which
combines the two. This allows a single command to be executed on multiple
maxscale instances. Added accompanying code for checking responsiveness of
all maxscale instances and handling synchronization of the check
results. The code uses ECMAScript 2016 native promises to do this.

Added a configurable timeout to all requests. This should allow users to
interact with MaxScale over slow and laggy networks.

Before each executed command, all hosts given as parameters are pinged to
make sure they are alive. This should reduce the possibility of partial
execution of commands due to failed MaxScales.

The results of requests are grouped by the values of the hosts
option. This allows users to compare results of multiple servers with
relative ease.

Fixed reversion of the default credentials from mariadb:admin to
admin:mariadb.
This commit is contained in:
Markus Mäkelä 2017-07-10 23:14:36 +03:00
parent 11c8493167
commit 2670ca36a0
2 changed files with 75 additions and 41 deletions

View File

@ -114,44 +114,52 @@ module.exports = function() {
}
// Helper for converting endpoints to acutal URLs
this.getUri = function(endpoint, options) {
var base = 'http://';
this.getUri = function(host, endpoint) {
var base = 'http://'
var argv = this.program.argv
if (argv.secure) {
base = 'https://';
base = 'https://'
}
return base + argv.user + ':' + argv.password + '@' +
argv.host + ':' + argv.port + '/v1/' + endpoint;
return base + argv.user + ':' + argv.password + '@' + host + '/v1/' + endpoint
}
// Helper for executing requests and handling their responses
this.doRequest = function(resource, cb, obj) {
pingCluster()
.then(function() {
var argv = this.program.argv
argv.hosts.forEach(function(host) {
args = obj || {}
args.uri = getUri(host, resource)
args.json = true
args.timeout = argv.timeout
args = obj || {}
args.uri = getUri(resource),
args.json = true
request(args, function(err, resp, res) {
if (err) {
// Failed to request
logError(JSON.stringify(err, null, 4))
} else if (resp.statusCode == 200 && cb) {
// Request OK, returns data
cb(res)
} else if (resp.statusCode == 204) {
// Request OK, no data
console.log(colors.green('OK'))
} else {
// Unexpected return code, probably an error
var errstr = resp.statusCode + ' ' + resp.statusMessage
if (res) {
errstr += ' ' + JSON.stringify(res, null, 4)
}
logError(errstr)
}
})
request(args, function(err, resp, res) {
if (err) {
// Failed to request
console.log(colors.yellow(host) + ':')
logError(JSON.stringify(err, null, 4))
} else if (resp.statusCode == 200 && cb) {
// Request OK, returns data
console.log(colors.yellow(host) + ':')
cb(res)
} else if (resp.statusCode == 204) {
// Request OK, no data
console.log(colors.yellow(host) + ': ' + colors.green('OK'))
} else {
// Unexpected return code, probably an error
var errstr = resp.statusCode + ' ' + resp.statusMessage
if (res) {
errstr += ' ' + JSON.stringify(res, null, 4)
}
console.log(colors.yellow(host) + ':')
logError(errstr)
}
})
})
})
}
this.updateValue = function(resource, key, value) {
@ -180,3 +188,27 @@ function getTable(headobj) {
head: headobj
})
}
function pingMaxScale(host) {
return new Promise(function(resolve, reject) {
request('http://' + host + '/v1', function(err, resp, res) {
if (err) {
reject(err)
} else if (resp.statusCode != 200) {
reject(resp.statusCode + ' ' + resp.statusMessage)
} else {
resolve()
}
})
})
}
function pingCluster() {
var promises = []
this.program.argv.hosts.forEach(function(i) {
promises.push(pingMaxScale(i))
})
return Promise.all(promises)
}

View File

@ -18,31 +18,26 @@ const maxctrl_version = '1.0.0';
program
.version(maxctrl_version)
.group(['u', 'p', 'h', 'p', 'P', 's'], 'Global Options:')
.group(['u', 'p', 'h', 's', 't'], 'Global Options:')
.option('u', {
alias:'user',
global: true,
default: 'mariadb',
default: 'admin',
describe: 'Username to use',
type: 'string'
})
.option('p', {
alias: 'password',
describe: 'Password for the user',
default: 'admin',
default: 'mariadb',
type: 'string'
})
.option('h', {
alias: 'host',
describe: 'MaxScale hostname',
default: 'localhost',
type: 'string'
})
.option('P', {
alias: 'port',
describe: 'MaxScale REST API port',
default: 8989,
type: 'number'
alias: 'hosts',
describe: 'List of MaxScale hosts. The hosts must be in ' +
'<hostname>:<port> format and each host must be separated by spaces.',
default: 'localhost:8989',
type: 'array'
})
.option('s', {
alias: 'secure',
@ -50,6 +45,13 @@ program
default: 'false',
type: 'boolean'
})
.option('t', {
alias: 'timeout',
describe: 'Request timeout in milliseconds',
default: '10000',
type: 'number'
})
.command(require('./lib/list.js'))
.command(require('./lib/show.js'))
.command(require('./lib/set.js'))