MXS-1300: Add initial implementation of MaxCtrl
This is the administrative client that uses the REST API to communicate with MaxScale. It is written in Node.js as it can handle the JSON format data returned by the REST API natively. Currently only list and show functionality is implemented.
This commit is contained in:
parent
61241f9e07
commit
1148ed9876
155
client/maxctrl/common.js
Normal file
155
client/maxctrl/common.js
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2020-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
var _ = require('lodash-getpath')
|
||||
var request = require('request');
|
||||
var colors = require('colors/safe');
|
||||
var Table = require('cli-table');
|
||||
var assert = require('assert')
|
||||
|
||||
module.exports = function() {
|
||||
const maxctrl_version = '1.0.0';
|
||||
|
||||
// Common options for all commands
|
||||
this.program = require('yargs');
|
||||
this.program
|
||||
.group(['u', 'p', 'h', 'p', 'P', 's'], 'Global Options:')
|
||||
.option('u', {
|
||||
alias:'user',
|
||||
global: true,
|
||||
default: 'mariadb',
|
||||
describe: 'Username to use',
|
||||
type: 'string'
|
||||
})
|
||||
.option('p', {
|
||||
alias: 'password',
|
||||
describe: 'Password for the user',
|
||||
default: 'admin',
|
||||
type: 'string'
|
||||
})
|
||||
.option('h', {
|
||||
alias: 'host',
|
||||
describe: 'The hostname or address where MaxScale is located',
|
||||
default: 'localhost',
|
||||
type: 'string'
|
||||
})
|
||||
.option('P', {
|
||||
alias: 'port',
|
||||
describe: 'The port where MaxScale REST API listens on',
|
||||
default: 8989,
|
||||
type: 'number'
|
||||
})
|
||||
.option('s', {
|
||||
alias: 'secure',
|
||||
describe: 'Enable TLS encryption of connections',
|
||||
default: 'false',
|
||||
type: 'boolean'
|
||||
})
|
||||
.version(maxctrl_version)
|
||||
.help()
|
||||
|
||||
// Request a resource collection and format it as a table
|
||||
this.getCollection = function (resource, headers, parts) {
|
||||
|
||||
doRequest(resource, function(res) {
|
||||
var table = getTable(headers)
|
||||
|
||||
res.data.forEach(function(i) {
|
||||
row = []
|
||||
|
||||
parts.forEach(function(p) {
|
||||
var v = _.getPath(i, p, "")
|
||||
|
||||
if (Array.isArray(v)) {
|
||||
v = v.join(", ")
|
||||
}
|
||||
row.push(v)
|
||||
})
|
||||
|
||||
table.push(row)
|
||||
})
|
||||
|
||||
console.log(table.toString())
|
||||
})
|
||||
}
|
||||
|
||||
// Request a single resource and format it as a key-value list
|
||||
this.getResource = function (resource, fields) {
|
||||
|
||||
doRequest(resource, function(res) {
|
||||
var table = new Table()
|
||||
|
||||
fields.forEach(function(i) {
|
||||
var k = Object.keys(i)[0]
|
||||
var path = i[k]
|
||||
var v = _.getPath(res.data, path, "")
|
||||
|
||||
if (Array.isArray(v) && typeof(v[0]) != 'object') {
|
||||
v = v.join(", ")
|
||||
} else if (typeof(v) == 'object') {
|
||||
v = JSON.stringify(v, null, 4)
|
||||
}
|
||||
|
||||
var o = {}
|
||||
o[k] = v
|
||||
table.push(o)
|
||||
})
|
||||
|
||||
console.log(table.toString())
|
||||
})
|
||||
}
|
||||
|
||||
// Helper for converting endpoints to acutal URLs
|
||||
this.getUri = function(endpoint, options) {
|
||||
var base = 'http://';
|
||||
var argv = this.program.argv
|
||||
|
||||
if (argv.secure) {
|
||||
base = 'https://';
|
||||
}
|
||||
|
||||
return base + argv.user + ':' + argv.password + '@' +
|
||||
argv.host + ':' + argv.port + '/v1/' + endpoint;
|
||||
}
|
||||
|
||||
// Helper for executing requests and handling their responses
|
||||
this.doRequest = function(resource, cb) {
|
||||
request({
|
||||
uri: getUri(resource),
|
||||
json: true
|
||||
}, function(err, resp, res) {
|
||||
if (resp.statusCode == 200) {
|
||||
cb(res)
|
||||
} else if (resp.statusCode == 204) {
|
||||
console.log(colors.green("OK"))
|
||||
} else {
|
||||
console.log("Error:", resp.statusCode, resp.statusMessage)
|
||||
if (res) {
|
||||
console.log(res)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a table-like array for output. The parameter is an array of header names
|
||||
function getTable(headobj) {
|
||||
|
||||
for (i = 0; i < headobj.length; i++) {
|
||||
headobj[i] = colors.cyan(headobj[i])
|
||||
}
|
||||
|
||||
return new Table({
|
||||
head: headobj
|
||||
})
|
||||
}
|
70
client/maxctrl/lib/list.js
Normal file
70
client/maxctrl/lib/list.js
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2020-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
require('../common.js')()
|
||||
|
||||
exports.command = 'list <command>'
|
||||
exports.desc = 'List objects'
|
||||
exports.handler = function() {}
|
||||
exports.builder = function(yargs) {
|
||||
yargs
|
||||
.command('servers', 'List servers', {}, function() {
|
||||
|
||||
getCollection('servers',
|
||||
['Server', 'Address', 'Port', 'Connections', 'Status'],
|
||||
['id',
|
||||
'attributes.parameters.address',
|
||||
'attributes.parameters.port',
|
||||
'attributes.statistics.connections',
|
||||
'attributes.status'])
|
||||
})
|
||||
.command('services', 'List services', {}, function() {
|
||||
getCollection('services',
|
||||
['Service', 'Router', 'Connections', 'Total Connections', 'Servers'],
|
||||
['id',
|
||||
'attributes.router',
|
||||
'attributes.connections',
|
||||
'attributes.total_connections',
|
||||
'relationships.servers.data[].id'])
|
||||
})
|
||||
.command('monitors', 'List monitors', {}, function() {
|
||||
getCollection('monitors',
|
||||
['Monitor', 'Status', 'Servers'],
|
||||
['id',
|
||||
'attributes.state',
|
||||
'relationships.servers.data[].id'])
|
||||
})
|
||||
.command('sessions', 'List sessions', {}, function() {
|
||||
getCollection('sessions',
|
||||
['Id', 'Service', 'User', 'Host'],
|
||||
['id',
|
||||
'relationships.services.data[].id',
|
||||
'attributes.user',
|
||||
'attributes.remote'])
|
||||
})
|
||||
.command('filters', 'List filters', {}, function() {
|
||||
getCollection('filters',
|
||||
['Filter', 'Service', 'Module'],
|
||||
['id',
|
||||
'relationships.services.data[].id',
|
||||
'attributes.module'])
|
||||
})
|
||||
.command('modules', 'List loaded modules', {}, function() {
|
||||
getCollection('maxscale/modules',
|
||||
['Module', 'Type', 'Version'],
|
||||
['id',
|
||||
'attributes.module_type',
|
||||
'attributes.version'])
|
||||
})
|
||||
.help()
|
||||
}
|
87
client/maxctrl/lib/show.js
Normal file
87
client/maxctrl/lib/show.js
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2020-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
require('../common.js')()
|
||||
|
||||
exports.command = 'show <command>'
|
||||
exports.desc = 'Show objects'
|
||||
exports.handler = function() {}
|
||||
exports.builder = function(yargs) {
|
||||
yargs
|
||||
.command('server <server>', 'Show server', {}, function(argv) {
|
||||
getResource('servers/' + argv.server, [
|
||||
{'Server': 'id'},
|
||||
{'Address': 'attributes.parameters.address'},
|
||||
{'Port': 'attributes.parameters.port'},
|
||||
{'Status': 'attributes.status'},
|
||||
{'Services': 'relationships.services.data[].id'},
|
||||
{'Monitors': 'relationships.monitors.data[].id'},
|
||||
{'Master ID': 'attributes.master_id'},
|
||||
{'Node ID': 'attributes.node_id'},
|
||||
{'Slave Server IDs': 'attributes.slaves'},
|
||||
{'Statistics': 'attributes.statistics'}
|
||||
])
|
||||
})
|
||||
.command('service <service>', 'Show service', {}, function(argv) {
|
||||
getResource('services/' + argv.service, [
|
||||
{'Service': 'id'},
|
||||
{'Router': 'attributes.router'},
|
||||
{'Started At': 'attributes.started'},
|
||||
{'Current Connections': 'attributes.connections'},
|
||||
{'Total Connections': 'attributes.total_connections'},
|
||||
{'Servers': 'relationships.servers.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Router Diagnostics': 'attributes.router_diagnostics'}
|
||||
])
|
||||
})
|
||||
.command('monitor <monitor>', 'Show monitor', {}, function(argv) {
|
||||
getResource('monitors/' + argv.monitor, [
|
||||
{'Monitor': 'id'},
|
||||
{'Status': 'attributes.state'},
|
||||
{'Servers': 'relationships.servers.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Monitor Diagnostics': 'attributes.monitor_diagnostics'}
|
||||
])
|
||||
})
|
||||
.command('session <session>', 'Show session', {}, function(argv) {
|
||||
getResource('sessions/' + argv.session, [
|
||||
{'Id': 'id'},
|
||||
{'Service': 'relationships.services.data[].id'},
|
||||
{'Status': 'attributes.state'},
|
||||
{'User': 'attributes.user'},
|
||||
{'Host': 'attributes.remote'},
|
||||
{'Connected': 'attributes.connected'},
|
||||
{'Idle': 'attributes.idle'}
|
||||
])
|
||||
})
|
||||
.command('filter <filter>', 'Show filter', {}, function(argv) {
|
||||
getResource('filters/' + argv.filter, [
|
||||
{'Filter': 'id'},
|
||||
{'Module': 'attributes.module'},
|
||||
{'Services': 'relationships.services.data[].id'},
|
||||
{'Parameters': 'attributes.parameters'}
|
||||
])
|
||||
})
|
||||
.command('module <module>', 'Show loaded module', {}, function(argv) {
|
||||
getResource('maxscale/modules/' + argv.module, [
|
||||
{'Module': 'id'},
|
||||
{'Type': 'attributes.module_type'},
|
||||
{'Version': 'attributes.version'},
|
||||
{'Maturity': 'attributes.status'},
|
||||
{'Description': 'attributes.description'},
|
||||
{'Parameters': 'attributes.parameters'},
|
||||
{'Commands': 'attributes.commands'}
|
||||
])
|
||||
})
|
||||
.help()
|
||||
}
|
21
client/maxctrl/maxctrl.js
Normal file
21
client/maxctrl/maxctrl.js
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
|
||||
*
|
||||
* Change Date: 2020-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
require('./common.js')()
|
||||
|
||||
'use strict';
|
||||
|
||||
program
|
||||
.command(require('./lib/list.js'))
|
||||
.command(require('./lib/show.js'))
|
||||
.demandCommand(1, 'At least one command is required')
|
||||
.argv
|
25
client/maxctrl/package.json
Normal file
25
client/maxctrl/package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "maxctrl",
|
||||
"version": "1.0.0",
|
||||
"description": "MaxScale Administrative Client",
|
||||
"repository": "https://github.com/mariadb-corporation/MaxScale",
|
||||
"main": "maxctrl.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"maxscale"
|
||||
],
|
||||
"bin": {
|
||||
"maxctrl": "./maxctrl.js"
|
||||
},
|
||||
"author": "MariaDB Corporation Ab",
|
||||
"license": "SEE LICENSE IN ../../LICENSE.TXT",
|
||||
"dependencies": {
|
||||
"cli-table": "^0.3.1",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash-getpath": "^0.2.4",
|
||||
"request": "^2.81.0",
|
||||
"yargs": "^8.0.2"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user