Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Migrate Alerting Kibana pluign to the new Kibana Platform #209

Merged
merged 51 commits into from Nov 21, 2020
Merged

Migrate Alerting Kibana pluign to the new Kibana Platform #209

merged 51 commits into from Nov 21, 2020

Conversation

ftianli-amzn
Copy link

@ftianli-amzn ftianli-amzn commented Nov 18, 2020

Issue #, if available:
#208

Description of changes:

Migrate the whole plugin to the new Kibana platform.
Compatible with Kibana 7.9.1
Reference: the offical migration guide https://github.com/elastic/kibana/blob/master/src/core/MIGRATION.md

Main changes:

  1. Change the entry-point and definition of the the browser side code and server side code, now, there is no architectural difference between a plugin in the browser and a plugin on the server.
  2. Create a new manifest file kibana.json, which used for identifying the plugin, instead of package.json
  3. In browser side: Create a CoreContext to replace the existing AppContext to share the core services globally. Most common services in Kibana are provided by core now, such as chrome, http, notifications, and uiSettings etc. I'm using props to pass the values of them to other components.
  4. In server side: Change the way of adding new routes for the plugin APIs, and the way of handling the routes to what Kibana defines, because hapi.js server and request objects are not exposed to the plugin anymore.

Testing:

  1. Unit tests passed.
  2. Installed the plugin in an ODFE 1.11 cluster and did manual testing:
    Almost all the APIs with users in different backend role, and the style in dark mode.

Note:
Please use yarn start or yarn start -oss in the Kibana root directory to start Kibana with the pluign.
If you want to build the plugin, please do after running yarn start (to get the target folder generated).

TODOs:

  1. Review the CSS style in public/less/main.less and migrate the necessary style to SASS, as Less is not supported in Kibana "new platform" anymore.
  2. Correct outdated content in TRANSLATION.Md.
  3. Review "scripts" in package.json
  4. Review .kibana-plugin-helpers.json after upgrading to compatible with Kibana 7.10

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Tianli Feng added 30 commits October 23, 2020 17:33
…ht path, and using the correct http requst path in Monitors.test.js
@@ -279,7 +283,7 @@ class DefineMonitor extends Component {
content = (
<ExtractionQuery
response={JSON.stringify(response || '', null, 4)}
isDarkMode={this.isDarkMode}
isDarkMode={this.context.isDarkMode}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason why you pass other core services (notifications, httpClient) via props, but get isDarkMode via context here instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the same question goes for all places where you are using context instead of props.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking look at the PR.
It depends on the frequency of using these property. The property isDarkMode is used very few, so I didn't passed it by props.
httpClient is passed via props everywhere since the plugin created, and I didn't change that to prevent making the PR bigger.
For notifications, it's used frequently, so I passed it with httpClient by props. While, in the files related to "Email notification", notifications needs to be passed very deeply, where it's not needed in the middle ,so I used context instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks a little messy. If needed, I think I could pass them all via "props" to keep the PR simple.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, makes sense. Personally, I think for overall style it would probably be better to do one or the other - if some services need to be passed deeply, I think a good change could be removing the props and consuming everything via context like what you've done for isDarkMode. More info here.

Could be a separate PR later to try to standardize this, just my thoughts

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, the style should be consistent. As all the httpClient has been passed by "props", I have changed all the notifications and isDarkMode to be passed by "props". 😂. Btw, the AD related code in this repo is using the Context, and that's a reference to me.

if (response.data.ok) {
return response.data.emailGroups;
const response = await httpClient.get('../api/alerting/destinations/email_groups', {
query: { search: searchText, size: 200 },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated to these changes - rather than hardcoding a limit of 200 here, declare as a constant somewhere instead? Seems there's a few places where limits like this are hardcoded

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Make sense. I think I can change it based on your idea in another PR.

@@ -113,11 +113,14 @@ class DestinationsList extends React.Component {

isDeleteAllowed = async (type, id) => {
const { httpClient } = this.props;
const resp = await httpClient.post('../api/alerting/monitors/_search', {
const reuqestBody = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: typo here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I corrected it. Thanks.

public/plugin.js Outdated
id: PLUGIN_NAME,
title: 'Alerting',
description: 'Kibana Alerting Plugin',
// icon: `plugins/${PLUGIN_NAME}/images/alerting_icon.svg`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: probably fine to remove

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem 👍. I have removed.

Comment on lines +38 to +39
const alertingESClient = createAlertingCluster(core, globalConfig);
const adESClient = createAlertingADCluster(core, globalConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove createAlertingADCluster, you could combine these into one client as well. I guess this is more of a choice on how you want to modularize them. It seems fine the way it is too. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with combining the two files, if it works well. As I said, I didn't think much but try to keep as it is.😄 Yaliang added the file https://github.com/opendistro-for-elasticsearch/alerting-kibana-plugin/blame/master/server/clusters/alerting/createAlertingADCluster.js in the initial release of Anomaly Detection plugin.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I will ask his idea, and I found he didn't separate the 2 plugins in 2 clusters in AD's repo. 😅

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got an idea from Yaliang. The advantage of separating the two files is that the two plugins can be modified separately, IMO, like the Header configuration. (Though AD didn't separate the 2 cluster clients ... ) This part is written by Mihir originally, I think I will remain it for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes sense, sounds good

Comment on lines -246 to +245
const resp = await httpClient.get(`../api/alerting/alerts?${queryString.stringify(params)}`);
const resp = await httpClient.get('../api/alerting/alerts', { query: params });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to stringify this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little wired, in the HTTP request there can be params, query, and body, 3 types of value. Only the value of body needs to be formatted to JSON string. I didn't take much look into the source code, but just tried several times and find that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok that is good to know, thanks

Comment on lines +26 to +31
from: schema.number(),
size: schema.number(),
search: schema.string(),
sortField: schema.string(),
sortDirection: schema.string(),
state: schema.string(),
Copy link
Contributor

@lezzago lezzago Nov 19, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these fields always provided in Kibana when we call this api?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is only one place calling this API, which aims to get all the monitors to show in the dashboard.

const params = { from, size, search, sortField, sortDirection, state };
. The fields are all provided.
Btw, I write down all the field just make the validation to be accurate, we could use { query: schema.any()} at anytime to pass the validation.

export default class AlertService {
constructor(esDriver) {
this.esDriver = esDriver;
}

getAlerts = async (req, h) => {
getAlerts = async (context, req, res) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need context if it is not being used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's required params by the new route handler signature, details here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested that there will be Error: Internal Server Error without it.

@@ -0,0 +1,9 @@
{
"id": "opendistroAlerting",
"version": "1.11.0.2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we bump to 1.12.0.0 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do the version upgrade in another PR. Keeping the version number as 1.11 makes me possible to test the functionality in an ODFE 1.11 cluster after the migration. 😁

{
"id": "opendistroAlerting",
"version": "1.11.0.2",
"kibanaVersion": "kibana",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Specify kibana version as "kibana" will auto resolve as 7.10?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Yaliang, thanks a lot for reviewing my PR. In my mind, it will resolve as the version defined in package.json. Let me find some references.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It comes from "kbn-plugin-generator", in the template of the sample Kibana plugin, the value of "kibanaVersion" is set to "kibana". (https://github.com/elastic/kibana/blob/master/packages/kbn-plugin-generator/template/kibana.json.ejs).
As far as I see, it will get the version number from package.json.
Unfortunately, there is not much explanation for the manifest from Kibana. https://github.com/elastic/kibana/blob/master/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, it's ok if the build and yarn start test pass

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.👍 For the "kibanaVersion", probably it's not getting the version from "package.json" 🤔, because when I ran yarn build, the script prompts me to input the Kibana version manually.
I will investigate more about the "kibanaVersion", but it doesn't affect building the plugin.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, you may check @yizheliu-amazon 's build changes here - looks like you will want to change the serverSourcePattern in .kibana-plugin-helpers.json, and specify the plugin and kibana version in the Kibana manifest file. Not sure how the version verification and build naming has changed, with both the npm package.json and the Kibana manifest kibana.json specifying similar things now.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Tyler, thank you for your reminder. I didn't notice there is the name change in .kibana-plugin-helpers.json. 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change the "kibanaVersion" to the exact version number to avoid inputting version number manually when building through plugin-hlepers in another PR for ODFE 1.12.
As it's written in the migration guide, seems package.json doesn't relate much to the build process.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Also, per the new naming convention, can you change opendistroAlerting to opendistroAlertingKibana?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out. Sure, I just changed it in kibana.json in another branch, and will be in the following PR.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants