Upgrade monasca-kibana-plugin for Elkstack update

Story: 2006376
Task: 36179

Besides the plugin update, tests should get remade as well as Zuul jobs
due to plugin being built in a different way.

Change-Id: Id5d0bb53d10fa8823ceda2c8e922ea36b9b27501
This commit is contained in:
Arseni Lipinski 2019-09-04 18:18:19 +02:00 committed by Witek Bedyk
parent d26887599b
commit bfa95367e0
53 changed files with 874 additions and 1122 deletions

View File

@ -1,7 +1,7 @@
- project:
templates:
- nodejs4-jobs
check:
jobs:
- monascalog-python3-tempest:
voting: false
- monasca-tempest-log-python3-influxdb
gate:
jobs:
- monasca-tempest-log-python3-influxdb

View File

@ -1,15 +1,26 @@
Monasca Kibana plugin
=====================
Keystone authentication support and multi-tenancy for Kibana 4.6.x
Keystone authentication support and multi-tenancy for Kibana 7.3.x
Build
-----
After installing Node JS 10.15.2 and yarn, do the following to
initiate Kibana development environment.
::
npm install
npm run package
git clone https://github.com/elastic/kibana --branch 7.3
cd kibana
Clone the plugin to plugins/ inside the environment and run.
::
yarn kbn bootstrap
cd plugins/monasca-kibana-plugin
yarn build
Installation
------------
@ -35,9 +46,9 @@ Then install using the Kibana plugin manager tool:
::
$ /opt/kibana/bin/kibana plugin --install monasca-kibana-plugin --url file:///tmp/monasca-kibana-plugin-0.0.1.tar.gz
$ /opt/kibana/bin/kibana-plugin install file:///tmp/kibana/plugins/monasca-kibana-plugin/build/monasca-kibana-plugin-7.3.0.zip
Installing monasca-kibana-plugin
Attempting to transfer from file:///tmp/monasca-kibana-plugin-0.0.1.tar.gz
Attempting to transfer from file:///tmp/kibana/plugins/monasca-kibana-plugin/build/monasca-kibana-plugin-7.3.0.zip
Transferring 7567007 bytes....................
Transfer complete
Extracting plugin archive
@ -45,11 +56,16 @@ Then install using the Kibana plugin manager tool:
Optimizing and caching browser bundles...
Plugin installation complete
$ /opt/kibana/bin/kibana plugin --list
monasca-kibana-plugin
$ /opt/kibana/bin/kibana-plugin list
monasca-kibana-plugin@7.3.0
Now start/restart your Kibana server by running:
::
$ service kibana restart
Valuable resources:
- Kibana plugin notes - https://github.com/nreese/kibana-plugin-notes
- Elastic forum - https://discuss.elastic.co

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -32,12 +32,12 @@ var pkg = require('./package.json');
var packageName = pkg.name + '-' + pkg.version;
// relative location of Kibana install
var pathToKibana = '../kibana';
var pathToKibana = '../../kibana';
var buildDir = path.resolve(__dirname, 'build');
var targetDir = path.resolve(__dirname, 'target');
var buildTarget = path.resolve(buildDir, pkg.name);
var kibanaPluginDir = path.resolve(__dirname, pathToKibana, 'installedPlugins', pkg.name);
var kibanaPluginDir = path.resolve(__dirname, pathToKibana, 'plugins', pkg.name);
var exclude = [
'.git',

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -56,6 +56,11 @@ export default (kibana) => {
})
.default();
//Elasticsearch parameter added due to the fact that retrieving elasticsearch url via server.config() is impossible
const elasticsearch = Joi.object({
url: Joi.string().uri({scheme: ['http', 'https']})
}).default();
return Joi
.object({
enabled: Joi.boolean().default(true),
@ -65,7 +70,8 @@ export default (kibana) => {
defaultEventsTimeField: Joi.string().default('@timestamp'),
logsIndexPrefix: Joi.string().default('logs-<project_id>'),
eventsIndexPrefix: Joi.string().default('events-<project_id>'),
cookie: cookie
cookie: cookie,
elasticsearch: elasticsearch
})
.concat(deprecated_keystone)
.concat(valid_keystone)
@ -74,12 +80,11 @@ export default (kibana) => {
.default();
}
function init(server) {
server.log(['status', 'debug', 'keystone'], 'Initializing keystone plugin');
async function init(server) {
server.log(['MKP','status', 'debug', 'keystone'], 'Initializing keystone plugin');
binding(server).start();
session(server).start();
await session(server).start();
healthCheck(this, server).start();
server.log(['status', 'debug', 'keystone'], 'Initialized keystone plugin');
server.log(['MKP','status', 'debug', 'keystone'], 'Initialized keystone plugin');
}
};

View File

@ -1,45 +1,43 @@
{
"name": "monasca-kibana-plugin",
"version": "1.5.0",
"description": "Keystone authentication & multitenancy support for Kibana 4.6.x",
"author": "OpenStack",
"license": "Apache-2.0",
"keywords": [
"kibana",
"authentication",
"keystone",
"multitenancy",
"plugin"
],
"scripts": {
"start": "gulp dev",
"build": "gulp build",
"package": "gulp package",
"test": "gulp test",
"lint": "gulp lint"
"name": "monasca-kibana-plugin",
"version": "7.3.0",
"description": "Keystone authentication & multitenancy support for Kibana 7.3.x",
"main": "gulpfile.js",
"kibana": {
"version": "7.3.0",
"templateVersion": "1.0.0"
},
"engines": {
"node": "4.4.7",
"npm": "2.15.8"
},
"main": "gulpfile.js",
"dependencies": {
"hoek": "^4.0.1",
"keystone-v3-client": "~0.0.8",
"yar": "^7.x.x"
},
"repository": {
"type": "git",
"url": "https://github.com/openstack/monasca-kibana-plugin.git"
"scripts": {
"preinstall": "node ../../preinstall_check",
"kbn": "node ../../scripts/kbn",
"es": "node ../../scripts/es",
"lint": "eslint .",
"start": "plugin-helpers start",
"test:server": "plugin-helpers test:server",
"test:browser": "plugin-helpers test:browser",
"build": "plugin-helpers build"
},
"devDependencies": {
"babel-eslint": "^4.1.8",
"babel-preset-es2015": "^6.3.13",
"babel-register": "^6.4.3",
"@elastic/eslint-config-kibana": "link:../../packages/eslint-config-kibana",
"@elastic/eslint-import-resolver-kibana": "link:../../packages/kbn-eslint-import-resolver-kibana",
"@kbn/expect": "link:../../packages/kbn-expect",
"@kbn/plugin-helpers": "link:../../packages/kbn-plugin-helpers"
},
"dependencies": {
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-jest": "^22.4.1",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-mocha": "^5.3.0",
"eslint-plugin-no-unsanitized": "^3.0.2",
"eslint-plugin-prefer-object-spread": "^1.2.1",
"eslint-plugin-react": "^7.12.4",
"@hapi/wreck": "^15.0.1",
"bluebird": "^3.2.1",
"boom": "^2.8.0",
"chai": "^3.5.0",
"eslint-plugin-mocha": "^1.1.0",
"gulp": "^3.9.0",
"gulp-eslint": "^1.1.1",
"gulp-gzip": "^1.2.0",
@ -54,6 +52,9 @@
"rsync": "^0.4.0",
"semver": "^5.3.0",
"sinon": "^1.17.3",
"wreck": "^8.0.0"
"hoek": "^4.0.1",
"keystone-v3-client": "~0.0.8",
"@hapi/yar": "^9.2.x",
"request": "^2.88.0"
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -21,7 +21,8 @@ export const SESSION_TOKEN_CHANGED = `monasca-kibana-plugin-token-changed-${NOW_
export const TOKEN_CHANGED_VALUE = Symbol('token-changed');
export const RELOAD_MARKUP = `<html>
<head><script type="text/javascript">window.location.reload();</script></head>
<body>reloading...</body>
</html>`;
export const RELOAD_MARKUP = `
<html>
<head><script src="#" type="text/javascript">window.location.reload();</script></head>
<body>reloading...</body>
</html>`;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -36,7 +36,7 @@ module.exports = function healthcheck(plugin, server) {
}
};
server.on('stop', stop);
server.events.on('stop', stop);
return service;
@ -105,7 +105,7 @@ module.exports = function healthcheck(plugin, server) {
function getRequest() {
let required;
if (util.startsWith(keystoneUrl, 'https')) {
if (keystoneUrl.startsWith('https')) {
required = require('https');
} else {
required = require('http');
@ -121,7 +121,7 @@ module.exports = function healthcheck(plugin, server) {
port : getPort(),
method : 'GET'
};
if (util.startsWith(keystoneUrl, 'https')) {
if (keystoneUrl.startsWith('https')) {
params.rejectUnauthorized = false;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -12,17 +12,16 @@
* the License.
*/
import Boom from 'boom';
import Joi from 'joi';
import { SESSION_USER_KEY, RELOAD_MARKUP } from '../../const';
import {RELOAD_MARKUP, SESSION_USER_KEY} from '../../const';
import lookupToken from './token';
import RELOAD from './reload';
const NOOP = ()=> {
const NOOP = () => {
};
const SCHEMA = {
tokenOk : Joi.func().default(NOOP),
tokenOk: Joi.func().default(NOOP),
tokenBad: Joi.func().default(NOOP)
};
@ -43,15 +42,23 @@ export default (server, opts) => {
server.log(['status', 'debug', 'keystone'],
'Received error object from token lookup'
);
return reply(token);
return reply.unauthenticated(token);
} else if (token === RELOAD) {
// TODO: this part is basically ineffective now due to Kibana rejecting
// any HTML injection
server.log(['status', 'debug', 'keystone'],
'Received reload markup object from token lookup'
);
return reply(RELOAD_MARKUP).type('text/html');
return reply.response(RELOAD_MARKUP).type('text/html').takeover();
} else if (userObj && 'project' in userObj) {
server.log(['status','info','keystone'], `${token} already authorized`);
return reply.continue({credentials:token});
server.log(['status', 'info', 'keystone'], `${token} already authorized`);
return reply.authenticated(
{
credentials: token,
artifacts: {
project: userObj.project.id
}
});
}
server.log(['status', 'debug', 'keystone'],
@ -61,7 +68,7 @@ export default (server, opts) => {
return tokensApi
.validate({
headers: {
'X-Auth-Token' : token,
'X-Auth-Token': token,
'X-Subject-Token': token
}
})
@ -69,18 +76,24 @@ export default (server, opts) => {
(data) => {
userObj = data.data.token;
return callbackOk(token, userObj, session)
.then(()=> {
.then(() => {
server.log(['status', 'debug', 'keystone'],
`Auth process completed for user ${userObj.user.id}`);
return reply.continue({credentials: token});
return reply.authenticated({
credentials: token,
artifacts: {
project: userObj.project.id
}
});
});
})
.catch((error) => {
server.log(['_auth-error'], error);
return callbackBad(token, error, session)
.then((err)=> {
.then((err) => {
server.log(['status', 'error', 'keystone'], `Auth process did not complete for token ${token}`);
server.log(['status', 'error', 'keystone'], `${err}`);
return reply(Boom.wrap(err));
return reply.unauthenticated(err);
});
});
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -13,9 +13,11 @@
*/
import authenticateFactory from './_authenticate';
import verify from './verify'
export default (server, opts) => {
return {
authenticate: authenticateFactory(server, opts)
authenticate: authenticateFactory(server, opts),
verify: verify(server)
};
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -15,7 +15,6 @@
import Boom from 'boom';
import Promise from 'bluebird';
import kibanaIndex from '../kibana';
import defaultIndexPattern from '../kibana/defaultIndexPattern';
import userProjects from '../projects';
@ -36,11 +35,7 @@ export default (server) => {
session.set(SESSION_TOKEN_KEY, token);
session.set(SESSION_USER_KEY, userObj);
return Promise
.all([
userProjects(server, session, userObj),
kibanaIndex(server, userObj)
])
return userProjects(server, session, userObj)
.then(defaultIndexPattern(server, userObj))
.then(() => {
server.log(['status', 'info', 'keystone'], `User ${userObj.user.id} authorized with keystone`);
@ -49,7 +44,7 @@ export default (server) => {
.catch(err => {
server.log(['status', 'info', 'keystone'],
`Error caught in process of authorization, err was ${err}`);
throw err;
throw new Error(err);
});
}
@ -63,13 +58,11 @@ export default (server) => {
if (error.statusCode === 401) {
err = Boom.forbidden('\You\'re not logged in as a user who\'s authorized to access log information');
} else {
err = Boom.internal(
error.message || 'Unexpected error during Keystone communication',
{},
err = Boom.internal(error.message || 'Unexpected error during Keystone communication',
error.statusCode
);
}
return resolve(err);
resolve(err);
});
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -38,7 +38,8 @@ const HEADER_NAME = 'x-auth-token';
*/
module.exports = (server, request) => {
if (!request.yar || request.yar === null) {
if (!request.yar) {
server.log(['status', 'keystone', 'error'], 'Session is not enabled');
throw new Error('Session support is missing');
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -15,26 +15,24 @@
import Boom from 'boom';
import {
SESSION_PROJECTS_KEY,
SESSION_USER_KEY,
SESSION_TOKEN_CHANGED,
TOKEN_CHANGED_VALUE,
RELOAD_MARKUP
} from '../../const';
export default () => {
return (request, reply) => {
export default (server) => {
return async (request, reply) => {
let session = request.yar;
let userObj = session.get(SESSION_USER_KEY);
let tokenChanged = session.get(SESSION_TOKEN_CHANGED);
if (tokenChanged === TOKEN_CHANGED_VALUE) {
request.log(['status', 'info', 'keystone'],
'Detected that token has been changed, replaying the request'
);
//TODO: This part doesn't really have any effect now because Kibana won't allow HTML injection
server.log(['status', 'info', 'keystone'], 'Detected that token has been changed, replaying the request');
session.clear(SESSION_TOKEN_CHANGED);
return reply(RELOAD_MARKUP).type('text/html');
return reply.response(RELOAD_MARKUP).type('text/html');
} else if (userObj) {
let expiresAt = new Date(userObj.expires_at).valueOf();
let now = new Date().valueOf();
@ -44,19 +42,17 @@ export default () => {
session.reset();
return reply(Boom.unauthorized('User token has expired'));
} else {
return reply.continue({
request.yar.set({
credentials: userObj,
artifacts : {
projects: session.get(SESSION_PROJECTS_KEY)
},
log : {
log: {
tags: 'keystone ok'
}
});
return reply.continue;
}
}
// TODO(trebskit) should actually throw error here I guess
return reply.continue();
};
return reply.continue;
}
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -12,28 +12,25 @@
* the License.
*/
export default {
export default {
bind: (server) => {
server.log(['status', 'info', 'keystone'], 'Registering keystone-auth schema');
return Promise.all([
bindAuthScheme(server),
bindExt(server),
bindRouting(server)
]);
}
};
//I suppose the handler that would prevent user from deleting his default index pattern should be implemented as well
function bindRouting(server) {
const kibanaIndex = server.config().get('kibana.index');
return require('./routing')(server)
.then((route)=> {
route(server, 'GET', '/{paths*}');
route(server, 'POST', '/_mget');
route(server, 'POST', '/{index}/_search');
route(server, 'POST', '/{index}/_field_stats');
route(server, 'POST', '/_msearch');
route(server, 'POST', '/_search/scroll');
route(server, ['PUT', 'POST', 'DELETE'], '/' + kibanaIndex + '/{paths*}');
.then((route) => {
route(server, ['GET', 'POST'], '/{paths*}');
route(server, ['GET', 'POST'], '/{search_pattern}/_search');
route(server, 'GET', '/api/saved_objects/_find');
route(server, 'GET', '/api/kibana/management/saved_objects/_find');
route(server, 'POST', '/api/saved_objects/_bulk_get');
});
}
@ -44,21 +41,11 @@ function bindAuthScheme(server) {
require('./auth/scheme')
),
server.auth.strategy(
'session',
'keystone-session',
'keystone-token',
false,
require('./auth/strategy')(server)
)
]);
}
function bindExt(server) {
return Promise.all([
server.ext(
'onPreAuth',
require('./auth/verify')(server),
{after: ['yar']}
),
server.ext('onRequest', require('./verify')(server))
]);
}
//bindExt is removed due to verify being a part of authentication scheme and the other one was no longer relevant

View File

@ -1,57 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import semver from 'semver';
const VERSION_REGEX = /(\d+\.\d+\.\d+)\-rc(\d+)/i;
export default (server, doc) => {
const config = server.config();
if (/beta|snapshot/i.test(doc._id)) {
return false;
}
if (!doc._id) {
return false;
}
if (doc._id === config.get('pkg.version')) {
return false;
}
let packageRcRelease = Infinity;
let rcRelease = Infinity;
let packageVersion = config.get('pkg.version');
let version = doc._id;
let matches = doc._id.match(VERSION_REGEX);
let packageMatches = config.get('pkg.version').match(VERSION_REGEX);
if (matches) {
version = matches[1];
rcRelease = parseInt(matches[2], 10);
}
if (packageMatches) {
packageVersion = packageMatches[1];
packageRcRelease = parseInt(packageMatches[2], 10);
}
try {
if (semver.gte(version, packageVersion) && rcRelease >= packageRcRelease) {
return false;
}
} catch (e) {
return false;
}
return true;
};

View File

@ -1,107 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import { find } from 'lodash';
import Promise from 'bluebird';
import canUpgradeConfig from './_can_upgrade';
export default (server, indexName) => {
const config = server.config();
const client = server.plugins.elasticsearch.client;
const options = {
index: indexName,
type : 'config',
body : {
size: 1000,
sort: [
{
buildNum: {
order : 'desc',
ignore_unmapped: true
}
}
]
}
};
server.log(['status', 'debug', 'keystone'], `Configuring index ${indexName}`);
return client
.search(options)
.then(upgradeConfig(server, indexName))
.then(()=>{
return Promise
.delay(666)
.then(() => {
server.log(['status', 'debug', 'keystone'], `Index ${indexName} has been configured`);
return indexName;
});
})
.catch((err)=> {
throw new Error(`Configuring ${indexName} failed, error is ${err}`);
});
function upgradeConfig(server, indexName) {
const client = server.plugins.elasticsearch.client;
const config = server.config();
return (response) => {
if (response.hits.hits.length === 0) {
return client.create({
index: indexName,
type : 'config',
body : {
buildNum: config.get('pkg.buildNum')
},
id : config.get('pkg.version')
});
}
// if we already have a the current version in the index then we need to stop
var devConfig = find(response.hits.hits, function currentVersion(hit) {
return hit._id !== '@@version' && hit._id === config.get('pkg.version');
});
if (devConfig) {
return Promise.resolve();
}
// Look for upgradeable configs. If none of them are upgradeable
// then resolve with null.
let body = find(response.hits.hits, canUpgradeConfig.bind(null, server));
if (!body) {
return Promise.resolve();
}
// if the build number is still the template string (which it wil be in development)
// then we need to set it to the max interger. Otherwise we will set it to the build num
body._source.buildNum = config.get('pkg.buildNum');
server.log(['plugin', 'elasticsearch'], {
tmpl : 'Upgrade config from <%= prevVersion %> to <%= newVersion %>',
prevVersion: body._id,
newVersion : config.get('pkg.version')
});
return client.create({
index: indexName,
type : 'config',
body : body._source,
id : config.get('pkg.version')
});
};
}
};

View File

@ -1,76 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Boom from 'boom';
import { exists as indexExists } from './_exists';
export default (server, indexName) => {
const client = server.plugins.elasticsearch.client;
server.log(['status', 'info', 'keystone'], `Creating user index ${indexName}`);
return client.indices
.create({
index: indexName,
body : {
settings: {
number_of_shards: 1
},
mappings: {
config: {
properties: {
buildNum: {
type : 'string',
index: 'not_analyzed'
}
}
},
'index-pattern': {
properties: {
title: {
type: 'string'
},
timeFieldName: {
type: 'string'
},
notExpandable: {
type: 'boolean'
},
intervalName: {
type: 'string'
}
}
}
}
}
})
.catch((err)=> {
throw Boom.wrap(err, 500,
`Failed to create index ${indexName}`);
})
.then(() => {
return indexExists(server, indexName, 'yellow')
.catch((err)=> {
throw Boom.wrap(err, 500,
`Waiting for index ${indexName} to come online failed`);
})
.then(()=> {
server.log(['status', 'info', 'keystone'],
`Index ${indexName} has been created`);
return Promise.resolve(indexName);
});
});
};

View File

@ -1,38 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import kibanaIndex from './kibanaIndex';
export default (server, userObj) => {
const indexName = kibanaIndex(server, userObj);
return exists(server, indexName)
.then((resp) => {
return {indexName, resp};
});
};
export function exists(server, indexName, status) {
const es = server.plugins.elasticsearch.client;
const opts = {
timeout : '5s',
index : indexName,
ignore : [408],
waitForActiveShards: 1
};
if (status) {
opts.waitForStatus = status;
}
return es.cluster.health(opts);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {createSavedObject} from '../savedObjectsToolkit';
export async function createLogsIndexPattern(server, userObj) {
server.log(['status', 'info', 'keystone'],
`Creating default logs-index pattern for ${userObj.project.id}`);
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return await createIndexPattern(server, pattern);
}
export async function createEventsIndexPattern(server, userObj) {
server.log(['status', 'info', 'keystone'],
`Creating default events-index pattern for ${userObj.project.id}`);
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return await createIndexPattern(server, pattern);
}
async function createIndexPattern(server, pattern) {
let timeFieldName = server.config().get('monasca-kibana-plugin.defaultTimeField');
const type = 'index-pattern';
const params = {
title: pattern,
timeFieldName: timeFieldName,
};
const options = {
id: pattern,
overwrite: true
};
return createSavedObject(type, params, options)
.then(() => {
server.log(['status', 'info', 'keystone', 'create'], `Created ${type} ${pattern}`);
});
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {deleteSavedObject} from '../savedObjectsToolkit';
export async function deleteDefaultLogsIndex(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`);
server.log(['status', 'info', 'keystone'],
`Attempting to delete logs-index pattern ${pattern}`);
return await deleteSavedObject('index-pattern', pattern);
}
export async function deleteDefaultEventsIndex(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`);
server.log(['status', 'info', 'keystone'],
`Attempting to delete events-index pattern ${pattern}`);
return await deleteSavedObject('index-pattern', pattern);
}

View File

@ -1,58 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Promise from 'bluebird';
export default (server, indexName, userObj) => {
server.log(['status', 'info', 'keystone'],
`Creating default events-index pattern for ${indexName}`);
const client = server.plugins.elasticsearch.client;
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return client.create({
index: indexName,
type : 'index-pattern',
body : {
title: pattern,
timeFieldName : server.config().get('monasca-kibana-plugin.defaultEventsTimeField')
},
id : pattern
})
.then(() => {
return client.update({
index: indexName,
type: 'config',
id: server.config().get('pkg.version'),
body: {
doc: {
defaultIndex: pattern
}
}
});
})
.then(() => {
return client.indices.refresh({
index: indexName,
force: true
});
})
.then((response) => {
return Promise.resolve(response);
})
.catch((err)=> {
throw new Error(`Unable to setup events-index pattern, error is ${err}`);
});
};

View File

@ -1,30 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
export default (server, indexName, userObj) => {
const client = server.plugins.elasticsearch.client;
const options = {
index: indexName,
type : 'index-pattern',
id : server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*',
};
server.log(['status', 'info', 'keystone'],
`Deleting events-index pattern for ${indexName}...`);
return client
.delete(options)
.catch((err)=> {
throw new Error(`Deleting events-index pattern for ${indexName} failed, error is ${err}`);
});
};

View File

@ -1,33 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
export default (server, indexName, userObj) => {
const client = server.plugins.elasticsearch.client;
const options = {
index: indexName,
type : 'index-pattern',
id : server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*',
};
server.log(['status', 'debug', 'keystone'],
`Checking if default events-index pattern for ${indexName} exists...`);
return client
.exists(options)
.then((resp) => {
return resp;
})
.catch((err)=> {
throw new Error(`Getting events-index pattern for ${indexName} failed, error is ${err}`);
});
};

View File

@ -0,0 +1,47 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {find} from "../savedObjectsToolkit";
export async function defaultLogsIndexExists(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
server.log(['status', 'debug', 'keystone'],
`Checking if default logs-index pattern for ${userObj.project.id} exists...`);
return await patternExists(server, pattern);
}
export async function defaultEventsIndexExists(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
server.log(['status', 'debug', 'keystone'],
`Checking if default events-index pattern for ${userObj.project.id} exists...`);
return await patternExists(pattern);
}
async function patternExists(pattern) {
const params = {
type: 'index-pattern',
fields: ['title'],
};
return find(params)
.then((response) => {
return response.saved_objects.some(el => el.attributes.title === pattern);
}).catch((err) => {
throw new Error(`Checking if ${pattern} exists failed, error is ${err}`);
});
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
export default function (server, project) {
const logsEnabled = server.config().get('monasca-kibana-plugin.logs');
const eventsEnabled = server.config().get('monasca-kibana-plugin.events');
let output = [];
if (logsEnabled) {
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${project}`) + '*';
output += pattern;
}
if (eventsEnabled) {
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${project}`) + '*';
output += pattern;
}
return output;
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Promise from 'bluebird';
export default (server, indexName, userObj) => {
server.log(['status', 'info', 'keystone'],
`Creating default logs-index pattern for ${indexName}`);
const client = server.plugins.elasticsearch.client;
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return client.create({
index: indexName,
type : 'index-pattern',
body : {
title: pattern,
timeFieldName : server.config().get('monasca-kibana-plugin.defaultTimeField')
},
id : pattern
})
.then(() => {
return client.update({
index: indexName,
type: 'config',
id: server.config().get('pkg.version'),
body: {
doc: {
defaultIndex: pattern
}
}
});
})
.then(() => {
return client.indices.refresh({
index: indexName,
force: true
});
})
.then((response) => {
return Promise.resolve(response);
})
.catch((err)=> {
throw new Error(`Unable to setup logs-index pattern, error is ${err}`);
});
};

View File

@ -1,30 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
export default (server, indexName, userObj) => {
const client = server.plugins.elasticsearch.client;
const options = {
index: indexName,
type : 'index-pattern',
id : server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*',
};
server.log(['status', 'info', 'keystone'],
`Deleting logs-index pattern for ${indexName}...`);
return client
.delete(options)
.catch((err)=> {
throw new Error(`Deleting logs-index pattern for ${indexName} failed, error is ${err}`);
});
};

View File

@ -1,33 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
export default (server, indexName, userObj) => {
const client = server.plugins.elasticsearch.client;
const options = {
index: indexName,
type : 'index-pattern',
id : server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*',
};
server.log(['status', 'debug', 'keystone'],
`Checking if default logs-index pattern for ${indexName} exists...`);
return client
.exists(options)
.then((resp) => {
return resp;
})
.catch((err)=> {
throw new Error(`Getting logs-index pattern for ${indexName} failed, error is ${err}`);
});
};

View File

@ -0,0 +1,46 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {updateConfig} from "../savedObjectsToolkit";
export async function updateLogsConfig(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.logsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return await updateDefaultIndexPattern(server, pattern);
}
export async function updateEventsConfig(server, userObj) {
const pattern = server.config().get('monasca-kibana-plugin.eventsIndexPrefix')
.replace('<project_id>', `${userObj.project.id}`) + '*';
return await updateDefaultIndexPattern(server, pattern);
}
async function updateDefaultIndexPattern(server, pattern) {
const type = 'config';
const version = server.config().get('pkg.version');
const changes = {
defaultIndex: pattern
};
return await updateConfig(type, version, changes)
.catch((err) => {
server.log(['updateConfig'], `Can't set ${pattern} as default index pattern, error is: ${err}`);
})
.then(() => {
server.log(['updateConfig'], `Default index pattern is ${pattern}`);
});
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -12,72 +12,73 @@
* the License.
*/
import Promise from 'bluebird';
import defaultLogsIndexExists from './_logs_exists';
import defaultEventsIndexExists from './_events_exists';
import createLogsDefaultIndex from './_logs_create';
import createEventsDefaultIndex from './_events_create';
import deleteLogsDefaultIndex from './_logs_delete';
import deleteEventsDefaultIndex from './_events_delete';
import kibanaIndex from '../kibanaIndex';
import {createEventsIndexPattern, createLogsIndexPattern} from "./_create";
import {defaultEventsIndexExists, defaultLogsIndexExists} from "./_exists";
import {deleteDefaultEventsIndex, deleteDefaultLogsIndex} from "./_delete";
import {updateEventsConfig, updateLogsConfig} from "./_set_default_index_pattern";
export default (server, userObj) => {
return () => {
const indexName = kibanaIndex(server, userObj);
return defaultLogsIndexExists(server, indexName, userObj)
const project = userObj.project.id;
return defaultLogsIndexExists(server, userObj)
.then((logsExists) => {
if (server.config().get('monasca-kibana-plugin.logs')) {
server.log(['status', 'info', 'keystone'],
`Default logs-index pattern is enabled in kibana config file`);
if (!logsExists) {
server.log(['status', 'warning', 'keystone'],
`Default logs-index pattern for ${indexName} does not exist`);
return createLogsDefaultIndex(server, indexName, userObj);
`Default logs-index pattern for ${project} does not exist`);
return createLogsIndexPattern(server, userObj)
.then(() => {
return updateLogsConfig(server, userObj);
});
} else {
server.log(['status', 'info', 'keystone'],
`Default logs-index pattern for ${indexName} already exists`);
`Default logs-index pattern for ${project} already exists`);
}
} else {
server.log(['status', 'info', 'keystone'],
`Default logs-index pattern is disabled in kibana config file`);
if (logsExists) {
server.log(['status', 'warning', 'keystone'],
`Default logs-index pattern for ${indexName} exists, but it should not`);
return deleteLogsDefaultIndex(server, indexName, userObj);
`Default logs-index pattern for ${project} exists, but it should not`);
return deleteDefaultLogsIndex(server, userObj);
} else {
server.log(['status', 'info', 'keystone'],
`Default logs-index pattern for ${indexName} does not exist`);
`Default logs-index pattern for ${project} does not exist`);
}
}
})
.then(() => {
defaultEventsIndexExists(server, indexName, userObj)
defaultEventsIndexExists(server, userObj)
.then((eventsExists) => {
if (server.config().get('monasca-kibana-plugin.events')) {
server.log(['status', 'info', 'keystone'],
`Default events-index pattern is enabled in kibana config file`);
if (!eventsExists) {
server.log(['status', 'warning', 'keystone'],
`Default events-index pattern for ${indexName} does not exist`);
return createEventsDefaultIndex(server, indexName, userObj);
`Default events-index pattern for ${project} does not exist`);
return createEventsIndexPattern(server, userObj)
.then(() => {
return updateEventsConfig(server, userObj)
});
} else {
server.log(['status', 'info', 'keystone'],
`Default events-index pattern for ${indexName} already exists`);
`Default events-index pattern for ${project} already exists`);
}
} else {
server.log(['status', 'info', 'keystone'],
`Default events-index pattern is disabled in kibana config file`);
if (eventsExists) {
server.log(['status', 'warning', 'keystone'],
`Default events-index pattern for ${indexName} exists, but it should not`);
return deleteEventsDefaultIndex(server, indexName, userObj);
`Default events-index pattern for ${project} exists, but it should not`);
return deleteDefaultEventsIndex(server, userObj);
} else {
server.log(['status', 'info', 'keystone'],
`Default events-index pattern for ${indexName} does not exist`);
`Default events-index pattern for ${project} does not exist`);
}
}
});
});
})
})
};
};

View File

@ -1,39 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import indexExists from './_exists';
import createIndex from './_create';
import configureIndex from './_configure';
export default (server, userObj) => {
return doCheck();
function doCheck() {
return indexExists(server, userObj)
.then(({indexName, resp}) => {
if (!resp || resp.timed_out) {
server.log(['status', 'warning', 'keystone'], `Index ${indexName} does not exists`);
return createIndex(server, indexName);
}
if (resp.status === 'red') {
server.log(['status', 'warning', 'keystone'], `Shards not ready for index ${indexName}`);
return Promise.delay(2500).then(doCheck);
}
return Promise.resolve(indexName);
})
.then((indexName)=> {
return configureIndex(server, indexName);
});
}
};

View File

@ -1,29 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
/**
* Returns tenant/project-aware kibana index
*
* @param server server object
* @param userObj user details as retrieved from keystone
* @returns {string} project aware kibana index
*
*/
export default (server, userObj) => {
return `${server.config().get('kibana.index')}-${getProjectId(userObj)}`;
};
function getProjectId(userObj) {
return userObj.project.id;
}

View File

@ -0,0 +1,138 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
let savedObjectsClient;
export function initClients(server) {
const elasticsearchClient = server.plugins.elasticsearch.getCluster('admin').callWithInternalUser;
const {SavedObjectsClient, getSavedObjectsRepository} = server.savedObjects;
const internalRepository = getSavedObjectsRepository(elasticsearchClient);
savedObjectsClient = new SavedObjectsClient(internalRepository);
}
export function findWithMeta(server, params) {
const version = server.config().get('pkg.version');
params.fields ? params.fields.push('title') : params.fields = ['title'];
params.fields.push('visState');
return find(params)
.then((response) => {
response.saved_objects.forEach(el => _createMetaForSavedObject(el, version));
return response;
})
.catch((err) => {
throw new Error(err);
});
}
export async function bulkGetSavedObjects(params) {
return await savedObjectsClient.bulkGet(params)
.catch((err) => {
throw new Error(err);
});
}
function _createMetaForSavedObject(object, version) {
const inAppPrefix = '/app/kibana#';
const managementPrefix = '/management/kibana';
switch (object.type) {
case 'config':
object.meta = {
title: `Advanced Settings [${version}]`,
inAppUrl: {
path: `${inAppPrefix}${managementPrefix}/settings`,
uiCapabilitiesPath: "advancedSettings.show"
}
};
break;
case 'index-pattern':
object.meta = {
icon: 'indexPatternApp',
title: object.attributes.title,
editUrl: `${managementPrefix}/index_patterns/${object.title}`,
inAppUrl: {
path: `${inAppPrefix}${managementPrefix}/index_patterns/${object.id}`,
uiCapabilitiesPath: "management.kibana.index_patterns"
}
};
break;
case 'search':
object.meta = {
icon: 'search',
title: object.attributes.title,
editUrl: `${managementPrefix}/objects/savedSearches/${object.id}`,
inAppUrl: {
path: `${inAppPrefix}/discover/${object.id}`,
uiCapabilitiesPath: "discover.show"
}
};
break;
case 'visualization':
object.meta = {
icon: 'visualizeApp',
title: object.attributes.title,
editUrl: `${managementPrefix}/objects/savedVisualizations/${object.id}`,
inAppUrl: {
path: `${inAppPrefix}/visualize/edit/${object.id}`,
uiCapabilitiesPath: "visualize.show"
}
};
break;
case 'dashboard':
object.meta = {
icon: 'dashboardApp',
title: object.attributes.title,
editUrl: `${managementPrefix}/objects/savedDashboards/${object.id}`,
inAppUrl: {
path: `${inAppPrefix}/dashboard/${object.id}`,
uiCapabilitiesPath: "dashboard.show"
}
};
break;
default:
throw new Error(`Unknown saved object type ${object.type}`);
}
return object;
}
export async function createSavedObject(type, options, params) {
return await savedObjectsClient.create(type, options, params)
.catch((err) => {
throw new Error(`Unable to create ${type} ${options}, error is ${err}`);
});
}
export async function find(params) {
return await savedObjectsClient.find(params)
.catch((err) => {
throw new Error(`Can't perform search ${params}, error is: ${err}`);
});
}
export async function updateConfig(type, version, changes) {
return await savedObjectsClient.update(type, version, changes)
.catch((err) => {
throw new Error(`Can't update ${type} with ${changes}, error is: ${err}`);
});
}
export async function deleteSavedObject(type, id) {
return await savedObjectsClient.delete(type, id)
.catch((err) => {
throw new Error(`Can't delete ${type} ${id}, error is: ${err}`);
});
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -27,7 +27,8 @@ const readFile = (file) => fs.readFileSync(file, 'utf8');
module.exports = memoize(function (server) {
const config = server.config();
const target = url.parse(config.get('elasticsearch.url'));
const target = url.parse(config.get('monasca-kibana-plugin.elasticsearch.url'));
if (!/^https/.test(target.protocol)) {
return new http.Agent();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -16,27 +16,36 @@ import { PREFIX } from './_utils';
module.exports = (server, method, route) => {
const serverConfig = server.config();
const pre = '/elasticsearch';
const sep = route[0] === '/' ? '' : '/';
const path = `${PREFIX}${pre}${sep}${route}`;
let path;
if (/\/api.*\//.test(route)) {
path = `${PREFIX}${sep}${route}`;
} else {
path = `${PREFIX}${pre}${sep}${route}`;
}
server.log(['create-proxy-path'], path + '; ' + method);
let options;
switch (route) {
case '/_mget':
options = require('./routes/mget')(server, method, path);
case '/_search':
options = require('./routes/search')(server, method, path);
break;
case '/{paths*}':
options = require('./routes/paths')(server, method, path);
case '/{search_pattern}/_search':
options = require('./routes/pattern_search')(server, method, path);
break;
case '/api/saved_objects/_bulk_get':
options = require('./routes/bulk_get')(server, method, path);
break;
default:
if (route === `/${serverConfig.get('kibana.index')}/{paths*}`) {
options = require('./routes/kibana_index')(server, method, path);
if (/\/api.*\/saved_objects\/_find/.test(route)) {
options = require('./routes/find')(server, method, path);
} else {
options = require('./routes/default')(server, method, path);
}
break;
}
return server.route(options);
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -23,10 +23,10 @@ import { PREFIX } from './_utils';
export default (server, request) => {
const config = server.config();
const path = request.path.replace(`${PREFIX}/elasticsearch`, '');
const path = request.path.replace(`${PREFIX}`, '').replace(`/elasticsearch`, '');
const query = querystring.stringify(request.query);
let url = config.get('elasticsearch.url');
let url = config.get('monasca-kibana-plugin.elasticsearch.url');
if (path) {
if (/\/$/.test(url)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -12,16 +12,17 @@
* the License.
*/
import utils from '../../util';
import {isRouted, requestPath} from '../../util';
import { PREFIX } from './_utils';
module.exports = function reRoute(server) {
return (request, reply) => {
const requestPath = utils.requestPath(request);
if (utils.isESRequest(request)) {
server.log(['status', 'debug', 'keystone'], `Routing ${requestPath} onto ${PREFIX}${requestPath}`);
request.setUrl(`${PREFIX}${requestPath}`);
const path = requestPath(request);
if (isRouted(request)) {
server.log(['status', 'debug', 'keystone'], `Routing ${path} onto ${PREFIX}${path}`);
request.setUrl(`${PREFIX}${path}`);
}
return reply.continue();
return reply.continue;
};
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -13,19 +13,20 @@
*/
import createAgent from './_create_agent';
import {bulkGetSavedObjects} from "../kibana/savedObjectsToolkit";
export const PREFIX = '/mt';
export function getOpts(server, request, url, payload) {
let options = {
headers : {},
redirects : true,
passThrough : true,
xforward : true,
timeout : 1000 * 60 * 3,
headers: {},
redirects: true,
passThrough: true,
xforward: true,
search_timeout: '10s',
localStatePassThrough: false,
agent : createAgent(server),
agent: createAgent(server),
};
let protocol = url.split(':', 1)[0];
@ -35,7 +36,7 @@ export function getOpts(server, request, url, payload) {
if (options.passThrough) {
options.headers = require('hoek').clone(request.headers);
delete options.headers.host;
//delete options.headers.host;
if (options.acceptEncoding === false) {
delete options.headers['accept-encoding'];
}
@ -46,11 +47,11 @@ export function getOpts(server, request, url, payload) {
request.info.remotePort) {
options.headers['x-forwarded-for'] = (options.headers['x-forwarded-for'] ?
options.headers['x-forwarded-for'] + ',' : '') + request.info.remoteAddress;
options.headers['x-forwarded-for'] + ',' : '') + request.info.remoteAddress;
options.headers['x-forwarded-port'] = (options.headers['x-forwarded-port'] ?
options.headers['x-forwarded-port'] + ',' : '') + request.info.remotePort;
options.headers['x-forwarded-port'] + ',' : '') + request.info.remotePort;
options.headers['x-forwarded-proto'] = (options.headers['x-forwarded-proto'] ?
options.headers['x-forwarded-proto'] + ',' : '') + protocol;
options.headers['x-forwarded-proto'] + ',' : '') + protocol;
}
const contentType = request.headers['content-type'];
@ -68,3 +69,60 @@ export function parsePayload(request) {
}
return JSON.parse(payload.toString('utf-8'));
}
function isAllowedSavedObject(element, patterns) {
let references = [];
switch (element.type) {
case 'index-pattern':
return patterns.includes(element.id);
case 'config':
return true;
case 'visualization':
case 'search':
references = element.references.filter(element => patterns.includes(element.id));
return references.length > 0;
default:
return false;
}
}
// We have to retrieve savedObjects once again because some of the searches may not contain the references of references
// Dashboard would be allowed only if it references saved objects accessible to the user
function isAllowedDashboard(element, patterns) {
const dashboardRefs = element.references.map((el) => {
return {id: el.id, type: el.type}
});
return bulkGetSavedObjects(dashboardRefs)
.then((response) => {
let onlyAllowed = true;
const references = response.saved_objects.map((el) => el.references)[0];
references.forEach((hit) => {
if (!patterns.includes(hit.id)) onlyAllowed = false;
});
return onlyAllowed;
});
}
async function filterDashboards(object, patterns) {
let dashboards = [];
for (let element of object) {
if (element.type === 'dashboard' && await isAllowedDashboard(element, patterns)) {
dashboards.push(element);
}
}
return dashboards;
}
// Dashboards have to be processed separately because it's references in saved_objects
// don't contain the references to index-pattern
// Dashboard is deemed allowed only if it contains allowed references only.
export async function filterResponse(data, patterns) {
let savedObjects = data.saved_objects.filter(el => isAllowedSavedObject(el, patterns));
let savedDashboards = await filterDashboards(data.saved_objects, patterns);
data.saved_objects = savedObjects.concat(savedDashboards);
return data;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at

View File

@ -0,0 +1,42 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {bulkGetSavedObjects} from '../../kibana/savedObjectsToolkit';
import getAllowedPatterns from '../../kibana/defaultIndexPattern/_get_allowed_patterns'
import {SESSION_USER_KEY} from '../../../const';
export default function (server, method, path) {
return {
method: method,
path: path,
config: {
auth: 'keystone-session',
},
handler: handler
};
async function handler(request, reply) {
const userObj = request.yar.get(SESSION_USER_KEY);
const patterns = getAllowedPatterns(server, userObj.project.id);
const params = request.payload;
if (params.type === 'index-pattern') {
if (!patterns.includes(params.id)) {
server.log(['error', 'api-bulk-get'], `Index-pattern ${params.id} is not allowed`);
throw new Error(`Index-pattern ${params.id} is not allowed`);
}
}
return bulkGetSavedObjects(params);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -20,14 +20,17 @@ module.exports = function defaultHandler(server, method, path) {
method : method,
path : path,
config : {
auth : 'session'
auth : 'keystone-session'
},
handler: {
proxy: {
mapUri : (request, done) => {
mapUri : (request) => {
server.log(['route-handler-default'], request.url.path);
server.log(['status', 'debug', 'keystone'],
`mapUri for path ${request.path}`);
done(null, mapUri(server, request));
`mapUri for path ${request.url.path}`);
return {
uri: mapUri(server, request)
};
},
agent : createAgent(server),
passThrough: true,

View File

@ -0,0 +1,51 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import {findWithMeta} from '../../kibana/savedObjectsToolkit';
import {filterResponse} from "../_utils";
import {SESSION_USER_KEY} from '../../../const';
import getAllowedPatterns from '../../kibana/defaultIndexPattern/_get_allowed_patterns';
export default function (server, method, path) {
return {
method: method,
path: path,
config: {
auth: 'keystone-session',
},
handler: handler
};
async function handler(request, reply) {
const userObj = request.yar.get(SESSION_USER_KEY);
const project = userObj.project.id;
const patterns = getAllowedPatterns(server, project);
const params = request.query;
if (params.fields && !(params.fields instanceof Array)) {
params.fields = [params.fields];
}
return findWithMeta(server, params)
.then((response) => {
return filterResponse(response, patterns, server)
})
.then((response) => {
response.total = response.saved_objects.length;
return response;
})
.catch((e) => {
throw new Error(`Find route failed, error: ${e}`);
});
}
}

View File

@ -1,57 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Wreck from 'wreck';
import { SESSION_USER_KEY } from '../../../const';
import { getOpts, parsePayload } from '../_utils';
import kibanaIndex from '../../kibana/kibanaIndex';
import mapUri from '../_map_uri';
export default function (server, method, path) {
const defaultKibanaIndex = server.config().get('kibana.index');
return {
method : method,
path : path,
config : {
auth : 'session',
payload: {
output: 'data',
parse : false
}
},
handler: handler
};
function handler(request, reply) {
const url = getUrl(request);
const opts = getOpts(server, request, url, parsePayload(request));
return Wreck.request(request.method, url, opts, (err, res) => {
return reply(res).code(res.statusCode).passThrough(!!opts.passThrough);
});
}
function getUrl(request) {
const session = request.yar._store;
let url = mapUri(server, request).split('/');
let indexPos = url.findIndex((item) => item === defaultKibanaIndex);
url[indexPos] = kibanaIndex(server, session[SESSION_USER_KEY]);
return url.join('/');
}
}

View File

@ -1,69 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Boom from 'boom';
import Wreck from 'wreck';
import { SESSION_USER_KEY } from '../../../const';
import { getOpts, parsePayload } from '../_utils';
import kibanaIndex from '../../kibana/kibanaIndex';
import mapUri from '../_map_uri';
export default function (server, method, path) {
return {
method : method,
path : path,
config : {
auth : 'session',
payload: {
output: 'data',
parse : false
}
},
handler: handler
};
function handler(request, reply) {
const url = mapUri(server, request);
const session = request.yar._store;
const payload = parsePayload(request);
payload.docs.forEach((doc) => {
doc._index = kibanaIndex(server, session[SESSION_USER_KEY]);
});
const opts = getOpts(server, request, url, payload);
return Wreck.request(request.method, url, opts, (err, res) => {
if (err) {
server.log(
['status', 'error', 'keystone'],
`Failed to request ${url}, error is ${err}`);
return reply(Boom.wrap(err));
}
return Wreck.read(res, {json: true}, (err, body)=> {
if (err) {
server.log(
['status', 'error', 'keystone'],
`Failed to read response from ${url}, error is ${err}`);
return reply(Boom.wrap(err));
}
return reply(body)
.code(res.statusCode)
.passThrough(!!opts.passThrough);
});
});
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Wreck from 'wreck';
import Boom from 'boom';
import { SESSION_USER_KEY } from '../../../const';
import { getOpts } from '../_utils';
import kibanaIndex from '../../kibana/kibanaIndex';
import mapUri from '../_map_uri';
export default function (server, method, path) {
const defaultKibanaIndex = server.config().get('kibana.index');
const logIndexPostionInUrl = 3;
return {
method : method,
path : path,
config : {
tags: ['elasticsearch', 'multitenancy'],
auth: 'session'
},
handler: handler
};
function handler(request, reply) {
const session = request.yar._store;
let url = mapUri(server, request).split('/');
let kibanaIndexRequest = false;
let indexPos = url.findIndex((item) => item === defaultKibanaIndex);
let logsIndexPref = server.config().get('monasca-kibana-plugin.logsIndexPrefix');
let eventsIndexPref = server.config().get('monasca-kibana-plugin.eventsIndexPrefix');
logsIndexPref = logsIndexPref.replace('<project_id>', session[SESSION_USER_KEY].project.id);
eventsIndexPref = eventsIndexPref.replace('<project_id>', session[SESSION_USER_KEY].project.id);
server.log(['status', 'info', 'keystone'],
`Allowing only these Index-Prefix ${logsIndexPref}, ${eventsIndexPref}`);
if (indexPos > -1) {
url[indexPos] = kibanaIndex(server, session[SESSION_USER_KEY]);
kibanaIndexRequest = true;
} else if (url.length > logIndexPostionInUrl
&& !(url[logIndexPostionInUrl].startsWith(logsIndexPref)
|| url[logIndexPostionInUrl].startsWith(eventsIndexPref))) {
return reply(Boom.unauthorized('User does not have access to this resource'));
}
url = url.join('/');
const opts = getOpts(server, request, url);
return Wreck.request(request.method, url, opts, (err, res) => {
return Wreck.read(res, {json: true}, (err, body)=> {
let newData = {};
if (kibanaIndexRequest) {
let tenantAwareIndex = Object.keys(body)[0];
newData[defaultKibanaIndex] = body[tenantAwareIndex];
} else {
newData = body;
}
return reply(newData)
.code(res.statusCode)
.passThrough(!!opts.passThrough);
});
});
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Wreck from '@hapi/wreck';
import {SESSION_USER_KEY} from '../../../const';
import {getOpts} from '../_utils';
import getAllowedPatterns from '../../kibana/defaultIndexPattern/_get_allowed_patterns';
import mapUri from '../_map_uri';
export default function (server, method, path) {
return {
method: method,
path: path,
config: {
auth: 'keystone-session',
},
handler: handler
};
async function handler(request, reply) {
const session = request.yar;
let url = mapUri(server, request).split('/');
let project = session.get(SESSION_USER_KEY).project.id;
let logsIndexPref = server.config().get('monasca-kibana-plugin.logsIndexPrefix');
let eventsIndexPref = server.config().get('monasca-kibana-plugin.eventsIndexPrefix');
logsIndexPref = logsIndexPref.replace('<project_id>', project);
eventsIndexPref = eventsIndexPref.replace('<project_id>', project);
server.log(['status', 'info', 'keystone'],
`Allowing only these Index-Prefix ${logsIndexPref}, ${eventsIndexPref}`);
url = url.join('/');
const opts = getOpts(server, request, url, request.payload);
const patterns = getAllowedPatterns(server, project);
try {
const rawResponse = await Wreck.request(request.method, url, opts);
const body = await Wreck.read(rawResponse, opts);
let response = JSON.parse(body.toString());
if (response._shards.total > 0) {
let indexHits = response.aggregations.indices.buckets;
response.aggregations.indices.buckets =
indexHits.filter(elem => patterns.includes(elem.key));
}
return reply.response(response).code(rawResponse.statusCode).passThrough(!!opts.passThrough);
} catch (e) {
throw new Error(e);
}
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Wreck from '@hapi/wreck';
import {getOpts, parsePayload} from '../_utils';
import mapUri from '../_map_uri';
export default function (server, method, path) {
return {
method: method,
path: path,
config: {
auth: 'keystone-session',
},
handler: handler
};
async function handler(request, reply) {
const url = mapUri(server, request);
const payload = parsePayload(request);
const opts = getOpts(server, request, url, payload);
try {
const rawResponse = await Wreck.request(request.method, url, opts);
const body = await Wreck.read(rawResponse, opts);
let response = JSON.parse(body.toString());
return reply.response(response).code(rawResponse.statusCode)
.passThrough(!!opts.passThrough);
} catch (e) {
throw new Error(e);
}
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import Boom from 'boom';
import { SESSION_PROJECTS_KEY } from '../../const';
import util from '../../util';
const INDEX_PATTER_POS = 2;
module.exports = (request, reply) => {
const session = request.yar._store;
const requestPath = util.requestPath(request);
const splittedPath = requestPath.split('/');
let pattern = splittedPath[INDEX_PATTER_POS];
let projects = session[SESSION_PROJECTS_KEY];
if ('*' === pattern) {
return reply(Boom.badData('* as pattern is not supported at the moment'));
} else if (projects.filter(filter).length === 0) {
return reply(Boom.badData(`${pattern} do not match any project of current user`));
}
return reply.continue();
function filter(project) {
return new RegExp(`${project.id}.*`, 'gi').test(pattern);
}
};

View File

@ -1,48 +0,0 @@
/*
* Copyright 2016 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import { SESSION_USER_KEY } from '../../const';
import util from '../../util';
module.exports = (server) => {
return (request, reply) => {
const session = request.yar._store;
if (!(session && (SESSION_USER_KEY in session))) {
server.log(['status', 'warning', 'keystone'], 'Session not yet available');
return reply.continue();
}
let requestPath = util.requestPath(request);
let requestMethod = request.method;
if (util.isESRequest(request)) {
let handler;
if (isIndexPatternLookup()) {
handler = require('./_verify_index_pattern');
}
if (handler) {
return handler(request, reply);
}
}
return reply.continue();
function isIndexPatternLookup() {
let regExp = /\/elasticsearch\/.*\/_mapping\/field\/.*/;
return regExp.test(requestPath) && requestMethod.toLowerCase() === 'get';
}
};
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -11,40 +11,37 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
import yarCookie from 'yar';
import yarCookie from "@hapi/yar"
import multiTenancy from '../mt';
import {initClients} from "../mt/kibana/savedObjectsToolkit";
export default (server) => {
const config = server.config();
return {
start: ()=> {
server.register({
register: yarCookie,
options : {
start: async () => {
await server.register({
plugin: yarCookie,
options: {
maxCookieSize: 4096,
name : config.get('monasca-kibana-plugin.cookie.name'),
storeBlank : false,
cache : {
name: config.get('monasca-kibana-plugin.cookie.name'),
storeBlank: false,
cache: {
expiresIn: config.get('monasca-kibana-plugin.cookie.expiresIn')
},
cookieOptions: {
password : config.get('monasca-kibana-plugin.cookie.password'),
isSecure : config.get('monasca-kibana-plugin.cookie.isSecure'),
password: config.get('monasca-kibana-plugin.cookie.password'),
isSecure: config.get('monasca-kibana-plugin.cookie.isSecure'),
ignoreErrors: config.get('monasca-kibana-plugin.cookie.ignoreErrors'),
clearInvalid: false
}
}
}, (error) => {
if (!error) {
server.log(['status', 'info', 'keystone'], 'Session registered');
multiTenancy.bind(server);
} else {
server.log(['status', 'error', 'keystone'], error);
throw error;
}
}).catch((err) => {
throw new Error(err);
});
server.log(['status', 'info', 'keystone'], 'Session registered');
initClients(server);
await multiTenancy.bind(server);
}
};
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2016-2017 FUJITSU LIMITED
* Copyright 2020 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
@ -13,9 +13,8 @@
*/
module.exports = {
startsWith: startsWith,
requestPath: getRequestPath,
isESRequest: isESRequest,
isRouted: isRoutedRequest,
keystoneUrl: keystoneUrl
};
@ -37,20 +36,19 @@ function keystoneUrl(config) {
return url;
}
function startsWith(str) {
var prefixes = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < prefixes.length; ++i) {
if (str.lastIndexOf(prefixes[i], 0) === 0) {
return true;
}
}
return false;
}
function getRequestPath(request) {
return request.url.path;
}
function isESRequest(request) {
return startsWith(getRequestPath(request), '/elasticsearch');
return getRequestPath(request).startsWith('/elasticsearch');
}
function isSavedObjectsRequest(request) {
return /\/api.*\/saved_objects\/_/.test(getRequestPath(request));
}
function isRoutedRequest(request) {
return isESRequest(request) || isSavedObjectsRequest(request);
}