Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Notification Service #19236

Merged
merged 5 commits into from
May 22, 2018

Conversation

pickypg
Copy link
Member

@pickypg pickypg commented May 18, 2018

This adds a notification service to Kibana that can be used to send
asynchronous notifications, such as sending email and Slack messages,
which are intended to be configured via a combination of the
kibana.yml and Kibana keystore.

Once configured, the actions are automatically added to the notification
service and can be invoked via the server using the notificationService
singleton or HTTP to send it directly. See the included README for more
details.

NOTE: This feature is currently experimental.

@pickypg pickypg added WIP Work in progress :Sharing v7.0.0 enhancement New value added to drive a business result v6.4.0 labels May 18, 2018
@pickypg pickypg force-pushed the feature/add-notification-service branch 2 times, most recently from 8f8e063 to 2d62a71 Compare May 20, 2018 04:03
@elasticmachine
Copy link
Contributor

💔 Build Failed

@pickypg
Copy link
Member Author

pickypg commented May 20, 2018

Jenkins test this

Advanced Setting UI test failure and map server test failure.

@pickypg pickypg added review and removed WIP Work in progress labels May 20, 2018
@elastic elastic deleted a comment from elasticmachine May 21, 2018
@elastic elastic deleted a comment from elasticmachine May 21, 2018
@elastic elastic deleted a comment from elasticmachine May 21, 2018
@elastic elastic deleted a comment from elasticmachine May 21, 2018
@elastic elastic deleted a comment from elasticmachine May 21, 2018
@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Contributor

@stacey-gammon stacey-gammon left a comment

Choose a reason for hiding this comment

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

What beautiful code @pickypg! LGTM! Thanks for setting us off in the right direction.

* Invokes plugin modules to instantiate the Monitoring plugin for Kibana
*
* @param kibana {Object} Kibana plugin instance
* @return {Object} Monitoring UI Kibana plugin object
Copy link
Contributor

Choose a reason for hiding this comment

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

Should Monitoring => Notifications ?

*/
export class EmailAction extends Action {

constructor({ server, options = { }, defaults = { }, _nodemailer = nodemailer }) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Options and defaults should be mutually exclusive, right? Defaults can be overridden when triggering a new email action, but options can't, and that is the difference?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. I should have added docs for the parameters. :) Will fix.

Copy link
Member Author

Choose a reason for hiding this comment

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

I also removed the default for options since that means the server isn't defined.

return null;
}

export async function sendNotification(server, notificationService, actionId, data, reply, { _checkForErrors = checkForErrors } = { }) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is exposing _checkForErrors only because of tests? I think there is a way, perhaps if you put it into it's own file, that you can mock it so you don't have to expose it here just for testing purposes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I am not used to Jest yet, so I did not honestly consider mocking the import. I'll swap that around.

Copy link
Member Author

Choose a reason for hiding this comment

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

I ended up not changing this and instead documented the parameter's purpose (for tests). It's handy to control that function instead of having to mock all of the behaviors.

Copy link
Member Author

Choose a reason for hiding this comment

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

Which ... now that I typed it and reread it, I could do by mocking the import.

if (error === null) {
return action.performAction(data)
.then(result => reply(result.toJson()))
.catch(err => reply(wrap(err))); // by API definition, this should never hapepn as performAction isn't allow to throw errrors
Copy link
Contributor

Choose a reason for hiding this comment

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

hapepn = happen

*
* @returns {Object|undefined} The error response, or {@code undefined} if no error.
*/
getError() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This class looks so clean! I like that you expose the inner variables as functions rather than leaving them to be directly accessed. That was something I was going back and forth on with my panel actions/embeddable stuff. Any particular reason you like this approach best? I don't think we are very consistent about it. Just curious.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks!

I have been working with Typescript recently and it feels more appropriate to have a defined object rather than a bunch of arbitrary properties for a contract like this where some things are inferred. It also enables any future Actions to extend ActionResult rather than trying to figure out how to make a custom object that matches all of the same fields and their behavior (e.g., overriding isOk).

In terms of this code, even I am somewhat inconsistent. The missing fields response is a plain Javascript Object with a predictable structure. I thought about making a class out of it, but it doesn't need one because nothing is inferred or even dynamic about it -- it just needs a strict interface definition, which Typescript should bring us in pretty short order. Hopefully we'll develop better collective habits once we are able to embrace Typescript within the codebase.

Copy link
Contributor

Choose a reason for hiding this comment

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

You can still override properties without making getters (this.isOk = mycustomFunc in the super class), and I think you can still use a typescript interface to define variables as well as functions expected.

But last night I thought of a reason to prefer using getter functions - to give a place where you could put deprecation warnings if you ever wanted to get rid of some variables! At least that works well for a class that acts an a pluggable API.

Copy link
Member Author

Choose a reason for hiding this comment

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

this.isOk = mycustomFunc that's assuming isOk wasn't just ok as a field though. It's the whole concept of encapsulation coming from standard Object Oriented development. But I also like your explanation even more.

* Returns mode of the license (basic, gold etc.). This is the "effective" type of the license.
* @returns {string|undefined}
*/
getMode() {
Copy link
Contributor

Choose a reason for hiding this comment

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

How is this different from type, above?

Copy link
Member Author

Choose a reason for hiding this comment

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

TL;DR It's generally the same thing as type, but it's the one that you should check (same as isOneOf does above in this class).

mode is the operational mode that ES has enabled (the license types we're used to). Technically it can be different from type, but in general they're the exact same value. This comes back from GET /_xpack, which xpack_main uses as opposed to GET /_xpack/license, which reports the mode / type as the same value.

@elasticmachine
Copy link
Contributor

💚 Build Succeeded

Copy link
Contributor

@chrisdavies chrisdavies left a comment

Choose a reason for hiding this comment

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

LGTM. Have a look at the markdown -> html comment. Not sure about that, or what effect it has on email clients to send html emails that aren't actually html...

bcc: notification.bcc,
// email content
subject: notification.subject,
html: notification.markdown,
Copy link
Contributor

Choose a reason for hiding this comment

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

Setting html to a markdown seems incorrect. Is this intentional? Seems like you'd want to convert markdown -> html here.

Copy link
Member Author

Choose a reason for hiding this comment

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

My plan was that we would evolve the Markdown support to be rendered as HTML, but I did not want to focus on that for now since it meant more complexity that we don't need yet.

Enabling it does provide a lot of potential benefits, but it also creates some interesting problems that I wanted to push back on. Namely, if you include image attachments I suspect that many people will want to include them in the body of the email and I didn't want to box us out of something by overstepping here.

const attachments = [];

if (markdown) {
attachments.push({ text: markdown });
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we should send raw markdown here or convert to HTML. Similar to my comment in the email action. I honestly prefer raw markdown, so I'm OK with this. Just wanted to point out that we may want to support prettifying it here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Slack interprets Markdown on its own, so in this case I would not touch it.

pickypg added 5 commits May 22, 2018 17:32
This adds a notification service to Kibana that can be used to send
asynchronous notifications, such as sending email and Slack messages,
which are intended to be configured via a combination of the
`kibana.yml` and Kibana keystore.

Once configured, the actions are automatically added to the notification
service and can be invoked via the server using the `notificationService`
singleton or HTTP to send it directly. See the included README for more
details.
@pickypg pickypg force-pushed the feature/add-notification-service branch from 844eff1 to d76ba5e Compare May 22, 2018 21:32
@elasticmachine
Copy link
Contributor

💚 Build Succeeded

@pickypg pickypg merged commit f2ccf90 into elastic:master May 22, 2018
@pickypg pickypg deleted the feature/add-notification-service branch May 22, 2018 23:02
pickypg added a commit that referenced this pull request May 22, 2018
This adds a notification service to Kibana that can be used to send
asynchronous notifications, such as sending email and Slack messages,
which are intended to be configured via a combination of the
`kibana.yml` and Kibana keystore.

Once configured, the actions are automatically added to the notification
service and can be invoked via the server using the `notificationService`
singleton or HTTP to send it directly. See the included README for more
details.
@pickypg
Copy link
Member Author

pickypg commented May 22, 2018

6.x/6.4: e6a88e0

@pickypg pickypg mentioned this pull request May 22, 2018
tylersmalley pushed a commit to tylersmalley/kibana that referenced this pull request Oct 25, 2019
Originally added in elastic#19236 as part
of the notification service, however it's no longer used.

Signed-off-by: Tyler Smalley <[email protected]>
tylersmalley pushed a commit that referenced this pull request Oct 25, 2019
Originally added in #19236 as part
of the notification service, however it's no longer used.

Signed-off-by: Tyler Smalley <[email protected]>
tylersmalley pushed a commit to tylersmalley/kibana that referenced this pull request Oct 25, 2019
Originally added in elastic#19236 as part
of the notification service, however it's no longer used.

Signed-off-by: Tyler Smalley <[email protected]>
tylersmalley pushed a commit that referenced this pull request Oct 25, 2019
Originally added in #19236 as part
of the notification service, however it's no longer used.

Signed-off-by: Tyler Smalley <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New value added to drive a business result review v6.4.0 v7.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants