Introducing HipChat Action
An action capable of sending notifications to rooms and users on hipchat. This actions support three types of HipChat APIs: - `v1` - The (now deprecated) legacy API where a token can be registered at the group level, and the `v1` version of the API can be used. This API only supports room notification (users cannot be notified). multi-room notification is supported. - `integration` - The basic integration that one can create in HipChat (it is using the `v2` API version), where notifications can be sent to a single room. User notification is unsupported by this API - `user` - this API uses an API token of a specific user. An admin user can create an API token and configure it to have access to room notification and user private messaging. This API supports multi-room and multi-user notifications. The settings for `hipchat` are very similar to the `email` infrastructure in nature. It is possible to configure multiple/different hipchat account, each is associated with the api type (a.k.a profile) - can be `v1`, `integration` or `user`, and the respective `auth_token`. When configuring the action in the watch, one can specify what hipchat account they would like to use (when not specifying an account, the `default_account` will be used). Each account can also specify its own unique `host`/`port` for the hipchat server - for full flexibility. Closes elastic/elasticsearch#462 Original commit: elastic/x-pack-elasticsearch@9d9ee13542
This commit is contained in:
parent
78a70b5f65
commit
0731a98e97
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
|
@ -157,9 +157,9 @@ during its execution:
|
||||||
|
|
||||||
image::images/action-throttling.jpg[align="center"]
|
image::images/action-throttling.jpg[align="center"]
|
||||||
|
|
||||||
Watcher supports four action types: <<actions-email, Email>>,
|
Watcher supports five action types: <<actions-email, Email>>,
|
||||||
<<actions-webhook, Webhook>>, <<actions-index, Index>> and
|
<<actions-webhook, Webhook>>, <<actions-index, Index>>,
|
||||||
<<actions-logging, Logging>>.
|
<<actions-logging, Logging>> and <<actions-hipchat, HipChat>>
|
||||||
|
|
||||||
include::actions/email.asciidoc[]
|
include::actions/email.asciidoc[]
|
||||||
|
|
||||||
|
@ -168,3 +168,5 @@ include::actions/webhook.asciidoc[]
|
||||||
include::actions/index.asciidoc[]
|
include::actions/index.asciidoc[]
|
||||||
|
|
||||||
include::actions/logging.asciidoc[]
|
include::actions/logging.asciidoc[]
|
||||||
|
|
||||||
|
include::actions/hipchat.asciidoc[]
|
|
@ -0,0 +1,235 @@
|
||||||
|
[[actions-hipchat]]
|
||||||
|
==== HipChat Action
|
||||||
|
|
||||||
|
A watch <<actions, action>> that can connect to a https://www.hipchat.com[HipChat] server and send
|
||||||
|
messages to users and rooms of a specific group.
|
||||||
|
|
||||||
|
|
||||||
|
[[configuring-hipchat-actions]]
|
||||||
|
===== Configuring HipChat Actions
|
||||||
|
|
||||||
|
You configure hipchat actions in a watch's `actions` array. Action-specific attributes are
|
||||||
|
specified using the `hipchat` keyword.
|
||||||
|
|
||||||
|
The following snippet shows a simple hipchat action definition:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
--------------------------------------------------
|
||||||
|
"actions" : {
|
||||||
|
"notify-hipchat" : { <1>
|
||||||
|
"transform" : { ... }, <2>
|
||||||
|
"throttle_period" : "5m", <3>
|
||||||
|
"hipchat" : {
|
||||||
|
"to" : {
|
||||||
|
"room" : "server-status" <4>
|
||||||
|
},
|
||||||
|
"message" : "Encountered {{ctx.payload.hits.total}} errors in the last 5 minutes (facepalm)" <5>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
<1> The id of the action
|
||||||
|
<2> An optional <<transform, transform>> to transform the payload before executing the `webhook` action
|
||||||
|
<3> An optional <<actions-ack-throttle, throttle period>> for the action (5 minutes in this example)
|
||||||
|
<4> The room where the message is sent to
|
||||||
|
<5> The content of the message.
|
||||||
|
|
||||||
|
HipChat provides an extensive set of APIs via which Watcher sends messages to users and rooms. These APIs
|
||||||
|
are exposed via different integration mechanism. Watcher refers to these as *Profiles*, each can be identified
|
||||||
|
with its own unique name: `v1`, `integration` and `user`.
|
||||||
|
|
||||||
|
Different profiles support different features and require different set of configuration (both on watcher
|
||||||
|
side and on the HipChat server side).
|
||||||
|
|
||||||
|
Before using the `hipchat` action in a watch, Watcher's internal HipChat service needs to be configured. This
|
||||||
|
Service enable the configuration of multiple HipChat accounts. An HipChat Account defines the following:
|
||||||
|
|
||||||
|
* `name` - (required) uniquely identifies the account. HipChat actions may specify the name of the account with which
|
||||||
|
the messages should be sent.
|
||||||
|
* `profile` - (required) the profile that is associated with this account, effectively defining what APIs this account uses.
|
||||||
|
* `auth_token` - (required) the authentication token that is used to execute the HipChat API in the account.
|
||||||
|
* `host` - (optional) defines the host of the HipChat server. When not defined it fall back on the default host (see bellow)
|
||||||
|
* `port` - (optional) defines the port of the HipChat server. When not defined it fall back on the default port (see bellow)
|
||||||
|
* `message_defaults` - (optional) a set of settings to define the default settings of the messages that are sent via this account
|
||||||
|
* `room` - Some account are bound to a single room (messages that are sent using their associated profiles can only be
|
||||||
|
sent to a specific room). For those account, this setting defines the room the account is bound to.
|
||||||
|
|
||||||
|
Here's an example settings for HipChat service:
|
||||||
|
|
||||||
|
[source,yaml]
|
||||||
|
--------------------------------------------------
|
||||||
|
watcher.actions.hipchat:
|
||||||
|
default_account: v1
|
||||||
|
account:
|
||||||
|
account1:
|
||||||
|
profile: v1
|
||||||
|
auth_token: XXXXXXXXX
|
||||||
|
message_default:
|
||||||
|
color: yello
|
||||||
|
message_format: text
|
||||||
|
account2:
|
||||||
|
profile: integration
|
||||||
|
auth_token: YYYYYYYYY
|
||||||
|
room: mission-control
|
||||||
|
message_default:
|
||||||
|
color: red
|
||||||
|
message_format: text
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
[[hipchat-api-v1]]
|
||||||
|
===== `v1` Account
|
||||||
|
|
||||||
|
WARNING: This account uses a deprecated API and is expected to be removed by HipChat in the future.
|
||||||
|
|
||||||
|
The `v1` API was the first API HipChat ever exposed and therefore the most commonly used one. It is also the simplest
|
||||||
|
one to set up. To create the `v1` API token, please follow the instructions listed on https://www.hipchat.com/docs/api.
|
||||||
|
|
||||||
|
NOTE: User private messages are not supported by this API. If private messages is what you are after, please
|
||||||
|
consider the <<`user`>> API instead.
|
||||||
|
|
||||||
|
Once the an API is created, add the following settings in `elasticsearch.yml` file:
|
||||||
|
|
||||||
|
The following table lists the available fields when setting up the `hipchat` action for the `v1` API:
|
||||||
|
|
||||||
|
[[hipchat-api-v1-action-attributes]]
|
||||||
|
.v1 API Action Attributes
|
||||||
|
[options="header"]
|
||||||
|
|======
|
||||||
|
| Name |Required | Default | Description
|
||||||
|
| `from` | no | the watch id | The name that will appear as the sender of the notification
|
||||||
|
| `room` | yes | - | The room/s that the notification should go to. Accepts a string value or an array of string values.
|
||||||
|
| `message` | yes | - | The content of the notification message (size is limited by HipChat to 1000 characters)
|
||||||
|
| `message_format` | no | html* | The format of the message. Possible options are: `text` or `html`
|
||||||
|
| `color` | no | yellow* | The background color of the notification in the room
|
||||||
|
| `notify` | no | false | Indicates whether people in the room should be actively notified
|
||||||
|
|======
|
||||||
|
|
||||||
|
Here is an example for how it looks like as part of the action definition:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
--------------------------------------------------
|
||||||
|
"actions" : {
|
||||||
|
"notify-hipchat" : {
|
||||||
|
"transform" : { ... },
|
||||||
|
"throttle_period" : "5m",
|
||||||
|
"hipchat" : {
|
||||||
|
"account" : "v1-account",
|
||||||
|
"message" : {
|
||||||
|
"from" : "watcher",
|
||||||
|
"room" : [ "server-status", "infra-team" ],
|
||||||
|
"message" : "Encountered {{ctx.payload.hits.total}} errors in the last 5 minutes (facepalm)",
|
||||||
|
"message_format" : "text",
|
||||||
|
"color" : "red",
|
||||||
|
"notify" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
[[hipchat-api-integration]]
|
||||||
|
===== `integration` Accounts
|
||||||
|
|
||||||
|
This profiles uses HipChat https://www.hipchat.com/docs/apiv2/addons[Integrations]. More specifically,
|
||||||
|
it uses a built-in integration in HipChat that enables external systems to send notifications to a
|
||||||
|
specific room. To create the `integration` API token:
|
||||||
|
|
||||||
|
* For HipChat.com, please follow the "Build your own integration" https://www.hipchat.com/docs/apiv2[instructions]
|
||||||
|
* For HipChat Server, please follow the "Build your own integration" https://confluence.atlassian.com/hc/administering-hipchat-server/integrations-with-hipchat-server[instructions]
|
||||||
|
|
||||||
|
In both cases, the api token can be copied from the listed example (marked in red bellow)
|
||||||
|
|
||||||
|
image:images/hipchat-integration-example.png[]
|
||||||
|
|
||||||
|
NOTE: This API is the most limited APIs of the three as it only supports sending notifications to a single room and
|
||||||
|
does not support user private messages. If you are looking for multi-room notifications, please consider either
|
||||||
|
the <<hipchat-api-v1, `v1`>> or <<hipchat-api-user, `user`>> APIs. Only the latter supports user private
|
||||||
|
messages.
|
||||||
|
|
||||||
|
When creating an account with the `integration` profile, you must configure the `room` setting as part
|
||||||
|
of the account setting.
|
||||||
|
|
||||||
|
The following table lists the available fields when setting up the `hipchat` action an `integration` account:
|
||||||
|
|
||||||
|
[[hipchat-api-integration-action-attributes]]
|
||||||
|
.v1 API Action Attributes
|
||||||
|
[options="header"]
|
||||||
|
|======
|
||||||
|
| Name |Required | Default | Description
|
||||||
|
| `message` | yes | - | The content of the notification message (size is limited by HipChat to 1000 characters)
|
||||||
|
| `message_format` | no | html* | The format of the message. Possible options are: `text` or `html`
|
||||||
|
| `color` | no | yellow* | The background color of the notification in the room
|
||||||
|
| `notify` | no | false | Indicates whether people in the room should be actively notified
|
||||||
|
|======
|
||||||
|
|
||||||
|
Here is an example for how it looks like as part of the action definition:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
--------------------------------------------------
|
||||||
|
"actions" : {
|
||||||
|
"notify-hipchat" : {
|
||||||
|
"transform" : { ... },
|
||||||
|
"throttle_period" : "5m",
|
||||||
|
"hipchat" : {
|
||||||
|
"account" : "integration-account",
|
||||||
|
"message" : {
|
||||||
|
"message" : "Encountered {{ctx.payload.hits.total}} errors in the last 5 minutes (facepalm)",
|
||||||
|
"message_format" : "text",
|
||||||
|
"color" : "red",
|
||||||
|
"notify" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
[[hipchat-api-user]]
|
||||||
|
===== `user` Accounts
|
||||||
|
|
||||||
|
The `user` API is arguably the most flexible API. It is also safe to use as it and is based on HipChat's `v2` API version.
|
||||||
|
To use this API you will require to add a new HipChat user. With this the user in place, all messages sent via this
|
||||||
|
account will be sent on this user behalf (make sure you name the user appropriately). After creating the user, you need
|
||||||
|
to create an API token for it. To create a user token please follow the instructions on HipChat's online documentation.
|
||||||
|
////
|
||||||
|
TODO: could not find a good link for that... we might need to show screenshots of the UI
|
||||||
|
////
|
||||||
|
|
||||||
|
While not supported by `v1` and `integration` accounts, the `user` account enables private user notification.
|
||||||
|
|
||||||
|
The following table lists the available fields when setting up the `hipchat` action for the `user` API:
|
||||||
|
|
||||||
|
[[hipchat-api-user-action-attributes]]
|
||||||
|
.v1 API Action Attributes
|
||||||
|
[options="header"]
|
||||||
|
|======
|
||||||
|
| Name |Required | Default | Description
|
||||||
|
| `message` | yes | - | The content of the notification message (size is limited by HipChat to 1000 characters)
|
||||||
|
| `message_format` | no | html* | The format of the message. Possible options are: `text` or `html`
|
||||||
|
| `color` | no | yellow* | The background color of the notification in the room
|
||||||
|
| `notify` | no | false | Indicates whether people in the room should be actively notified
|
||||||
|
|======
|
||||||
|
|
||||||
|
Here is an example for how it looks like as part of the action definition:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
--------------------------------------------------
|
||||||
|
"actions" : {
|
||||||
|
"notify-hipchat" : {
|
||||||
|
"transform" : { ... },
|
||||||
|
"throttle_period" : "5m",
|
||||||
|
"hipchat" : {
|
||||||
|
"account" : "integration-account",
|
||||||
|
"message" : {
|
||||||
|
"room" : [ "mission-control", "devops" ],
|
||||||
|
"user" : "website-admin@example.com",
|
||||||
|
"message" : "Encountered {{ctx.payload.hits.total}} errors in the last 5 minutes (facepalm)",
|
||||||
|
"message_format" : "text",
|
||||||
|
"color" : "red",
|
||||||
|
"notify" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--------------------------------------------------
|
|
@ -20,6 +20,7 @@ import org.elasticsearch.script.ScriptModule;
|
||||||
import org.elasticsearch.shield.authz.AuthorizationModule;
|
import org.elasticsearch.shield.authz.AuthorizationModule;
|
||||||
import org.elasticsearch.watcher.actions.WatcherActionModule;
|
import org.elasticsearch.watcher.actions.WatcherActionModule;
|
||||||
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.InternalHipChatService;
|
||||||
import org.elasticsearch.watcher.client.WatcherClientModule;
|
import org.elasticsearch.watcher.client.WatcherClientModule;
|
||||||
import org.elasticsearch.watcher.condition.ConditionModule;
|
import org.elasticsearch.watcher.condition.ConditionModule;
|
||||||
import org.elasticsearch.watcher.execution.ExecutionModule;
|
import org.elasticsearch.watcher.execution.ExecutionModule;
|
||||||
|
@ -27,15 +28,7 @@ import org.elasticsearch.watcher.history.HistoryModule;
|
||||||
import org.elasticsearch.watcher.input.InputModule;
|
import org.elasticsearch.watcher.input.InputModule;
|
||||||
import org.elasticsearch.watcher.license.LicenseModule;
|
import org.elasticsearch.watcher.license.LicenseModule;
|
||||||
import org.elasticsearch.watcher.license.LicenseService;
|
import org.elasticsearch.watcher.license.LicenseService;
|
||||||
import org.elasticsearch.watcher.rest.action.RestAckWatchAction;
|
import org.elasticsearch.watcher.rest.action.*;
|
||||||
import org.elasticsearch.watcher.rest.action.RestDeleteWatchAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestExecuteWatchAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestGetWatchAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestHijackOperationAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestPutWatchAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestWatchServiceAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestWatcherInfoAction;
|
|
||||||
import org.elasticsearch.watcher.rest.action.RestWatcherStatsAction;
|
|
||||||
import org.elasticsearch.watcher.shield.ShieldIntegration;
|
import org.elasticsearch.watcher.shield.ShieldIntegration;
|
||||||
import org.elasticsearch.watcher.shield.WatcherShieldModule;
|
import org.elasticsearch.watcher.shield.WatcherShieldModule;
|
||||||
import org.elasticsearch.watcher.shield.WatcherUserHolder;
|
import org.elasticsearch.watcher.shield.WatcherUserHolder;
|
||||||
|
@ -142,6 +135,7 @@ public class WatcherPlugin extends Plugin {
|
||||||
InitializingService.class,
|
InitializingService.class,
|
||||||
LicenseService.class,
|
LicenseService.class,
|
||||||
InternalEmailService.class,
|
InternalEmailService.class,
|
||||||
|
InternalHipChatService.class,
|
||||||
HttpClient.class,
|
HttpClient.class,
|
||||||
WatcherSettingsValidation.class);
|
WatcherSettingsValidation.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ public interface Action extends ToXContent {
|
||||||
public enum Status implements ToXContent {
|
public enum Status implements ToXContent {
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
FAILURE,
|
FAILURE,
|
||||||
|
PARTIAL_FAILURE,
|
||||||
THROTTLED,
|
THROTTLED,
|
||||||
SIMULATED;
|
SIMULATED;
|
||||||
|
|
||||||
|
@ -95,7 +96,6 @@ public interface Action extends ToXContent {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Field {
|
interface Field {
|
||||||
ParseField STATUS = new ParseField("status");
|
|
||||||
ParseField REASON = new ParseField("reason");
|
ParseField REASON = new ParseField("reason");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.watcher.actions;
|
||||||
|
|
||||||
import org.elasticsearch.watcher.actions.email.EmailAction;
|
import org.elasticsearch.watcher.actions.email.EmailAction;
|
||||||
import org.elasticsearch.watcher.actions.email.service.EmailTemplate;
|
import org.elasticsearch.watcher.actions.email.service.EmailTemplate;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
import org.elasticsearch.watcher.actions.index.IndexAction;
|
import org.elasticsearch.watcher.actions.index.IndexAction;
|
||||||
import org.elasticsearch.watcher.actions.logging.LoggingAction;
|
import org.elasticsearch.watcher.actions.logging.LoggingAction;
|
||||||
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
||||||
|
@ -53,4 +54,27 @@ public final class ActionBuilders {
|
||||||
return LoggingAction.builder(text);
|
return LoggingAction.builder(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(String message) {
|
||||||
|
return hipchatAction(Template.inline(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(String account, String body) {
|
||||||
|
return hipchatAction(account, Template.inline(body));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(Template.Builder body) {
|
||||||
|
return hipchatAction(body.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(String account, Template.Builder body) {
|
||||||
|
return hipchatAction(account, body.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(Template body) {
|
||||||
|
return hipchatAction(null, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction.Builder hipchatAction(String account, Template body) {
|
||||||
|
return HipChatAction.builder(account, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,10 @@ import org.elasticsearch.watcher.actions.email.EmailActionFactory;
|
||||||
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.watcher.actions.email.service.HtmlSanitizer;
|
import org.elasticsearch.watcher.actions.email.service.HtmlSanitizer;
|
||||||
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatActionFactory;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatService;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.InternalHipChatService;
|
||||||
import org.elasticsearch.watcher.actions.index.IndexAction;
|
import org.elasticsearch.watcher.actions.index.IndexAction;
|
||||||
import org.elasticsearch.watcher.actions.index.IndexActionFactory;
|
import org.elasticsearch.watcher.actions.index.IndexActionFactory;
|
||||||
import org.elasticsearch.watcher.actions.logging.LoggingAction;
|
import org.elasticsearch.watcher.actions.logging.LoggingAction;
|
||||||
|
@ -28,6 +32,14 @@ public class WatcherActionModule extends AbstractModule {
|
||||||
|
|
||||||
private final Map<String, Class<? extends ActionFactory>> parsers = new HashMap<>();
|
private final Map<String, Class<? extends ActionFactory>> parsers = new HashMap<>();
|
||||||
|
|
||||||
|
public WatcherActionModule() {
|
||||||
|
registerAction(EmailAction.TYPE, EmailActionFactory.class);
|
||||||
|
registerAction(WebhookAction.TYPE, WebhookActionFactory.class);
|
||||||
|
registerAction(IndexAction.TYPE, IndexActionFactory.class);
|
||||||
|
registerAction(LoggingAction.TYPE, LoggingActionFactory.class);
|
||||||
|
registerAction(HipChatAction.TYPE, HipChatActionFactory.class);
|
||||||
|
}
|
||||||
|
|
||||||
public void registerAction(String type, Class<? extends ActionFactory> parserType) {
|
public void registerAction(String type, Class<? extends ActionFactory> parserType) {
|
||||||
parsers.put(type, parserType);
|
parsers.put(type, parserType);
|
||||||
}
|
}
|
||||||
|
@ -36,27 +48,17 @@ public class WatcherActionModule extends AbstractModule {
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
|
||||||
MapBinder<String, ActionFactory> parsersBinder = MapBinder.newMapBinder(binder(), String.class, ActionFactory.class);
|
MapBinder<String, ActionFactory> parsersBinder = MapBinder.newMapBinder(binder(), String.class, ActionFactory.class);
|
||||||
|
|
||||||
bind(EmailActionFactory.class).asEagerSingleton();
|
|
||||||
parsersBinder.addBinding(EmailAction.TYPE).to(EmailActionFactory.class);
|
|
||||||
|
|
||||||
bind(WebhookActionFactory.class).asEagerSingleton();
|
|
||||||
parsersBinder.addBinding(WebhookAction.TYPE).to(WebhookActionFactory.class);
|
|
||||||
|
|
||||||
bind(IndexActionFactory.class).asEagerSingleton();
|
|
||||||
parsersBinder.addBinding(IndexAction.TYPE).to(IndexActionFactory.class);
|
|
||||||
|
|
||||||
bind(LoggingActionFactory.class).asEagerSingleton();
|
|
||||||
parsersBinder.addBinding(LoggingAction.TYPE).to(LoggingActionFactory.class);
|
|
||||||
|
|
||||||
for (Map.Entry<String, Class<? extends ActionFactory>> entry : parsers.entrySet()) {
|
for (Map.Entry<String, Class<? extends ActionFactory>> entry : parsers.entrySet()) {
|
||||||
bind(entry.getValue()).asEagerSingleton();
|
bind(entry.getValue()).asEagerSingleton();
|
||||||
parsersBinder.addBinding(entry.getKey()).to(entry.getValue());
|
parsersBinder.addBinding(entry.getKey()).to(entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(ActionRegistry.class).asEagerSingleton();
|
bind(ActionRegistry.class).asEagerSingleton();
|
||||||
|
|
||||||
bind(HtmlSanitizer.class).asEagerSingleton();
|
bind(HtmlSanitizer.class).asEagerSingleton();
|
||||||
bind(EmailService.class).to(InternalEmailService.class).asEagerSingleton();
|
bind(EmailService.class).to(InternalEmailService.class).asEagerSingleton();
|
||||||
|
|
||||||
|
bind(HipChatService.class).to(InternalHipChatService.class).asEagerSingleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -79,13 +79,15 @@ public class InternalEmailService extends AbstractLifecycleComponent<InternalEma
|
||||||
Settings.Builder builder = Settings.builder();
|
Settings.Builder builder = Settings.builder();
|
||||||
String prefix = "watcher.actions.email.service";
|
String prefix = "watcher.actions.email.service";
|
||||||
for (String setting : settings.getAsMap().keySet()) {
|
for (String setting : settings.getAsMap().keySet()) {
|
||||||
if (setting.startsWith("watcher.actions.email.service")) {
|
if (setting.startsWith(prefix)) {
|
||||||
builder.put(setting.substring(prefix.length()+1), settings.get(setting));
|
builder.put(setting.substring(prefix.length()+1), settings.get(setting));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (nodeSettings != settings) { // if it's the same settings, no point in re-applying it
|
||||||
for (String setting : nodeSettings.getAsMap().keySet()) {
|
for (String setting : nodeSettings.getAsMap().keySet()) {
|
||||||
if (setting.startsWith("watcher.actions.email.service")) {
|
if (setting.startsWith(prefix)) {
|
||||||
builder.put(setting.substring(prefix.length()+1), settings.get(setting));
|
builder.put(setting.substring(prefix.length() + 1), nodeSettings.get(setting));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accounts = createAccounts(builder.build(), logger);
|
accounts = createAccounts(builder.build(), logger);
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.watcher.actions.Action;
|
||||||
|
import org.elasticsearch.watcher.actions.ExecutableAction;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatAccount;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatService;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.SentMessages;
|
||||||
|
import org.elasticsearch.watcher.execution.WatchExecutionContext;
|
||||||
|
import org.elasticsearch.watcher.support.Variables;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
import org.elasticsearch.watcher.watch.Payload;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ExecutableHipChatAction extends ExecutableAction<HipChatAction> {
|
||||||
|
|
||||||
|
private final TemplateEngine templateEngine;
|
||||||
|
private final HipChatService hipchatService;
|
||||||
|
|
||||||
|
public ExecutableHipChatAction(HipChatAction action, ESLogger logger, HipChatService hipchatService, TemplateEngine templateEngine) {
|
||||||
|
super(action, logger);
|
||||||
|
this.hipchatService = hipchatService;
|
||||||
|
this.templateEngine = templateEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action.Result execute(final String actionId, WatchExecutionContext ctx, Payload payload) throws Exception {
|
||||||
|
|
||||||
|
HipChatAccount account = action.account != null ?
|
||||||
|
hipchatService.getAccount(action.account) :
|
||||||
|
hipchatService.getDefaultAccount();
|
||||||
|
|
||||||
|
// lets validate the message again, in case the hipchat service were updated since the
|
||||||
|
// watch/action were created.
|
||||||
|
account.validateParsedTemplate(ctx.id().watchId(), actionId, action.message);
|
||||||
|
|
||||||
|
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
|
||||||
|
HipChatMessage message = account.render(ctx.id().watchId(), actionId, templateEngine, action.message, model);
|
||||||
|
|
||||||
|
if (ctx.simulateAction(actionId)) {
|
||||||
|
return new HipChatAction.Result.Simulated(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
SentMessages sentMessages = account.send(message);
|
||||||
|
return new HipChatAction.Result.Executed(sentMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat;
|
||||||
|
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.ParseFieldMatcher;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.actions.Action;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.SentMessages;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatAction implements Action {
|
||||||
|
|
||||||
|
public static final String TYPE = "hipchat";
|
||||||
|
|
||||||
|
final @Nullable String account;
|
||||||
|
final HipChatMessage.Template message;
|
||||||
|
|
||||||
|
public HipChatAction(@Nullable String account, HipChatMessage.Template message) {
|
||||||
|
this.account = account;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
HipChatAction that = (HipChatAction) o;
|
||||||
|
|
||||||
|
if (!account.equals(that.account)) return false;
|
||||||
|
return message.equals(that.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = account.hashCode();
|
||||||
|
result = 31 * result + message.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
if (account != null) {
|
||||||
|
builder.field(Field.ACCOUNT.getPreferredName(), account);
|
||||||
|
}
|
||||||
|
builder.field(Field.MESSAGE.getPreferredName(), message);
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HipChatAction parse(String watchId, String actionId, XContentParser parser) throws IOException {
|
||||||
|
String account = null;
|
||||||
|
HipChatMessage.Template message = null;
|
||||||
|
|
||||||
|
String currentFieldName = null;
|
||||||
|
XContentParser.Token token;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.ACCOUNT)) {
|
||||||
|
if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
account = parser.text();
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("failed to parse [{}] action [{}/{}]. expected [{}] to be of type string, but found [{}] instead", TYPE, watchId, actionId, Field.ACCOUNT.getPreferredName(), token);
|
||||||
|
}
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.MESSAGE)) {
|
||||||
|
try {
|
||||||
|
message = HipChatMessage.Template.parse(parser);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse [{}] action [{}/{}]. failed to parse [{}] field", e, TYPE, watchId, actionId, Field.MESSAGE.getPreferredName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("failed to parse [{}] action [{}/{}]. unexpected token [{}]", TYPE, watchId, actionId, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message == null) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse [{}] action [{}/{}]. missing required [{}] field", TYPE, watchId, actionId, Field.MESSAGE.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HipChatAction(account, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder(String account, Template body) {
|
||||||
|
return new Builder(account, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Result {
|
||||||
|
|
||||||
|
class Executed extends Action.Result implements Result {
|
||||||
|
|
||||||
|
private final SentMessages sentMessages;
|
||||||
|
|
||||||
|
public Executed(SentMessages sentMessages) {
|
||||||
|
super(TYPE, status(sentMessages));
|
||||||
|
this.sentMessages = sentMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SentMessages sentMessages() {
|
||||||
|
return sentMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.field(type, sentMessages, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Status status(SentMessages sentMessages) {
|
||||||
|
boolean hasSuccesses = false;
|
||||||
|
boolean hasFailures = false;
|
||||||
|
for (SentMessages.SentMessage message : sentMessages) {
|
||||||
|
if (message.successful()) {
|
||||||
|
hasSuccesses = true;
|
||||||
|
} else {
|
||||||
|
hasFailures = true;
|
||||||
|
}
|
||||||
|
if (hasFailures && hasSuccesses) {
|
||||||
|
return Status.PARTIAL_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasFailures ? Status.FAILURE : Status.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Simulated extends Action.Result implements Result {
|
||||||
|
|
||||||
|
private final HipChatMessage message;
|
||||||
|
|
||||||
|
protected Simulated(HipChatMessage message) {
|
||||||
|
super(TYPE, Status.SIMULATED);
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatMessage getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.startObject(type)
|
||||||
|
.field(Field.MESSAGE.getPreferredName(), message, params)
|
||||||
|
.endObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder implements Action.Builder<HipChatAction> {
|
||||||
|
|
||||||
|
final String account;
|
||||||
|
final HipChatMessage.Template.Builder messageBuilder;
|
||||||
|
|
||||||
|
public Builder(String account, Template body) {
|
||||||
|
this.account = account;
|
||||||
|
this.messageBuilder = new HipChatMessage.Template.Builder(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addRooms(org.elasticsearch.watcher.support.template.Template... rooms) {
|
||||||
|
messageBuilder.addRooms(rooms);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addRooms(org.elasticsearch.watcher.support.template.Template.Builder... rooms) {
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] templates = new org.elasticsearch.watcher.support.template.Template[rooms.length];
|
||||||
|
for (int i = 0; i < rooms.length; i++) {
|
||||||
|
templates[i] = rooms[i].build();
|
||||||
|
}
|
||||||
|
return addRooms(templates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addRooms(String... rooms) {
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] templates = new org.elasticsearch.watcher.support.template.Template[rooms.length];
|
||||||
|
for (int i = 0; i < rooms.length; i++) {
|
||||||
|
templates[i] = Template.inline(rooms[i]).build();
|
||||||
|
}
|
||||||
|
return addRooms(templates);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Builder addUsers(org.elasticsearch.watcher.support.template.Template... users) {
|
||||||
|
messageBuilder.addUsers(users);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addUsers(org.elasticsearch.watcher.support.template.Template.Builder... users) {
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] templates = new org.elasticsearch.watcher.support.template.Template[users.length];
|
||||||
|
for (int i = 0; i < users.length; i++) {
|
||||||
|
templates[i] = users[i].build();
|
||||||
|
}
|
||||||
|
return addUsers(templates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addUsers(String... users) {
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] templates = new org.elasticsearch.watcher.support.template.Template[users.length];
|
||||||
|
for (int i = 0; i < users.length; i++) {
|
||||||
|
templates[i] = Template.inline(users[i]).build();
|
||||||
|
}
|
||||||
|
return addUsers(templates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFrom(String from) {
|
||||||
|
messageBuilder.setFrom(from);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFormat(HipChatMessage.Format format) {
|
||||||
|
messageBuilder.setFormat(format);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setColor(org.elasticsearch.watcher.support.template.Template color) {
|
||||||
|
messageBuilder.setColor(color);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setColor(org.elasticsearch.watcher.support.template.Template.Builder color) {
|
||||||
|
return setColor(color.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setColor(HipChatMessage.Color color) {
|
||||||
|
return setColor(color.asTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setNotify(boolean notify) {
|
||||||
|
messageBuilder.setNotify(notify);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatAction build() {
|
||||||
|
return new HipChatAction(account, messageBuilder.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Field {
|
||||||
|
ParseField ACCOUNT = new ParseField("account");
|
||||||
|
ParseField MESSAGE = new ParseField("message");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.logging.Loggers;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.actions.ActionFactory;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatAccount;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatService;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatActionFactory extends ActionFactory<HipChatAction, ExecutableHipChatAction> {
|
||||||
|
|
||||||
|
private final TemplateEngine templateEngine;
|
||||||
|
private final HipChatService hipchatService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public HipChatActionFactory(Settings settings, TemplateEngine templateEngine, HipChatService hipchatService) {
|
||||||
|
super(Loggers.getLogger(ExecutableHipChatAction.class, settings));
|
||||||
|
this.templateEngine = templateEngine;
|
||||||
|
this.hipchatService = hipchatService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return HipChatAction.TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
|
||||||
|
HipChatAction action = HipChatAction.parse(watchId, actionId, parser);
|
||||||
|
HipChatAccount account = hipchatService.getAccount(action.account);
|
||||||
|
if (account == null) {
|
||||||
|
throw new ElasticsearchParseException("could not parse [hipchat] action [{}/{}]. unknown hipchat account [{}]", watchId, account, action.account);
|
||||||
|
}
|
||||||
|
account.validateParsedTemplate(watchId, actionId, action.message);
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExecutableHipChatAction createExecutable(HipChatAction action) {
|
||||||
|
return new ExecutableHipChatAction(action, actionLogger, hipchatService, templateEngine);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class HipChatAccount {
|
||||||
|
|
||||||
|
public static final String AUTH_TOKEN_SETTING = "auth_token";
|
||||||
|
public static final String ROOM_SETTING = HipChatMessage.Field.ROOM.getPreferredName();
|
||||||
|
public static final String DEFAULT_ROOM_SETTING = "message_defaults." + HipChatMessage.Field.ROOM.getPreferredName();
|
||||||
|
public static final String DEFAULT_USER_SETTING = "message_defaults." + HipChatMessage.Field.USER.getPreferredName();
|
||||||
|
public static final String DEFAULT_FROM_SETTING = "message_defaults." + HipChatMessage.Field.FROM.getPreferredName();
|
||||||
|
public static final String DEFAULT_FORMAT_SETTING = "message_defaults." + HipChatMessage.Field.FORMAT.getPreferredName();
|
||||||
|
public static final String DEFAULT_COLOR_SETTING = "message_defaults." + HipChatMessage.Field.COLOR.getPreferredName();
|
||||||
|
public static final String DEFAULT_NOTIFY_SETTING = "message_defaults." + HipChatMessage.Field.NOTIFY.getPreferredName();
|
||||||
|
|
||||||
|
protected final ESLogger logger;
|
||||||
|
protected final String name;
|
||||||
|
protected final Profile profile;
|
||||||
|
protected final HipChatServer server;
|
||||||
|
protected final HttpClient httpClient;
|
||||||
|
protected final String authToken;
|
||||||
|
|
||||||
|
protected HipChatAccount(String name, Profile profile, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
this.name = name;
|
||||||
|
this.profile = profile;
|
||||||
|
this.server = new HipChatServer(settings, defaultServer);
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
this.authToken = settings.get(AUTH_TOKEN_SETTING);
|
||||||
|
if (this.authToken == null || this.authToken.length() == 0) {
|
||||||
|
throw new SettingsException("hipchat account [" + name + "] missing required [" + AUTH_TOKEN_SETTING + "] setting");
|
||||||
|
}
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String type();
|
||||||
|
|
||||||
|
public abstract void validateParsedTemplate(String watchId, String actionId, HipChatMessage.Template message) throws SettingsException;
|
||||||
|
|
||||||
|
public abstract HipChatMessage render(String watchId, String actionId, TemplateEngine engine, HipChatMessage.Template template, Map<String, Object> model);
|
||||||
|
|
||||||
|
public abstract SentMessages send(HipChatMessage message);
|
||||||
|
|
||||||
|
enum Profile implements ToXContent {
|
||||||
|
|
||||||
|
V1() {
|
||||||
|
@Override
|
||||||
|
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
return new V1Account(name, settings, defaultServer, httpClient, logger);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
INTEGRATION() {
|
||||||
|
@Override
|
||||||
|
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
return new IntegrationAccount(name, settings, defaultServer, httpClient, logger);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
USER() {
|
||||||
|
@Override
|
||||||
|
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
return new UserAccount(name, settings, defaultServer, httpClient, logger);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.value(name().toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String value() {
|
||||||
|
return name().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Profile parse(XContentParser parser) throws IOException {
|
||||||
|
return Profile.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Profile resolve(String value, Profile defaultValue) {
|
||||||
|
if (value == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return Profile.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Profile resolve(Settings settings, String setting, Profile defaultValue) {
|
||||||
|
return resolve(settings.get(setting), defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validate(String value) {
|
||||||
|
try {
|
||||||
|
Profile.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
return true;
|
||||||
|
} catch (IllegalArgumentException ilae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatAccount.Profile;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatAccounts {
|
||||||
|
|
||||||
|
private final Map<String, HipChatAccount> accounts;
|
||||||
|
private final String defaultAccountName;
|
||||||
|
|
||||||
|
public HipChatAccounts(Settings settings, HttpClient httpClient, ESLogger logger) {
|
||||||
|
HipChatServer defaultServer = new HipChatServer(settings);
|
||||||
|
Settings accountsSettings = settings.getAsSettings("account");
|
||||||
|
accounts = new HashMap<>();
|
||||||
|
for (String name : accountsSettings.names()) {
|
||||||
|
Settings accountSettings = accountsSettings.getAsSettings(name);
|
||||||
|
Profile profile = Profile.resolve(accountSettings, "profile", null);
|
||||||
|
if (profile == null) {
|
||||||
|
throw new SettingsException("missing [profile] setting for hipchat account [" + name + "]");
|
||||||
|
}
|
||||||
|
HipChatAccount account = profile.createAccount(name, accountSettings, defaultServer, httpClient, logger);
|
||||||
|
accounts.put(name, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
String defaultAccountName = settings.get("default_account");
|
||||||
|
if (defaultAccountName == null) {
|
||||||
|
if (accounts.isEmpty()) {
|
||||||
|
this.defaultAccountName = null;
|
||||||
|
} else {
|
||||||
|
HipChatAccount account = accounts.values().iterator().next();
|
||||||
|
logger.info("default hipchat account set to [{}]", account.name);
|
||||||
|
this.defaultAccountName = account.name;
|
||||||
|
}
|
||||||
|
} else if (!accounts.containsKey(defaultAccountName)) {
|
||||||
|
throw new SettingsException("could not find default hipchat account [" + defaultAccountName + "]");
|
||||||
|
} else {
|
||||||
|
this.defaultAccountName = defaultAccountName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the account associated with the given name. If there is not such account, {@code null} is returned.
|
||||||
|
* If the given name is {@code null}, the default account will be returned.
|
||||||
|
*
|
||||||
|
* @param name The name of the requested account
|
||||||
|
* @return The account associated with the given name, or {@code null} when requested an unkonwn account.
|
||||||
|
* @throws IllegalStateException if the name is null and the default account is null.
|
||||||
|
*/
|
||||||
|
public HipChatAccount account(String name) throws IllegalStateException {
|
||||||
|
if (name == null) {
|
||||||
|
if (defaultAccountName == null) {
|
||||||
|
throw new IllegalStateException("cannot find default hipchat account as no accounts have been configured");
|
||||||
|
}
|
||||||
|
name = defaultAccountName;
|
||||||
|
}
|
||||||
|
return accounts.get(name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,489 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.ParseFieldMatcher;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatMessage implements ToXContent {
|
||||||
|
|
||||||
|
final String body;
|
||||||
|
final @Nullable String[] rooms;
|
||||||
|
final @Nullable String[] users;
|
||||||
|
final @Nullable String from;
|
||||||
|
final @Nullable Format format;
|
||||||
|
final @Nullable Color color;
|
||||||
|
final @Nullable Boolean notify;
|
||||||
|
|
||||||
|
public HipChatMessage(String body, String[] rooms, String[] users, String from, Format format, Color color, Boolean notify) {
|
||||||
|
this.body = body;
|
||||||
|
this.rooms = rooms;
|
||||||
|
this.users = users;
|
||||||
|
this.from = from;
|
||||||
|
this.format = format;
|
||||||
|
this.color = color;
|
||||||
|
this.notify = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getRooms() {
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String[] getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Format getFormat() {
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Boolean getNotify() {
|
||||||
|
return notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
HipChatMessage that = (HipChatMessage) o;
|
||||||
|
|
||||||
|
if (!body.equals(that.body)) return false;
|
||||||
|
if (!Arrays.equals(rooms, that.rooms)) return false;
|
||||||
|
if (!Arrays.equals(users, that.users)) return false;
|
||||||
|
if (from != null ? !from.equals(that.from) : that.from != null) return false;
|
||||||
|
if (format != that.format) return false;
|
||||||
|
if (color != that.color) return false;
|
||||||
|
return !(notify != null ? !notify.equals(that.notify) : that.notify != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = body.hashCode();
|
||||||
|
result = 31 * result + (rooms != null ? Arrays.hashCode(rooms) : 0);
|
||||||
|
result = 31 * result + (users != null ? Arrays.hashCode(users) : 0);
|
||||||
|
result = 31 * result + (from != null ? from.hashCode() : 0);
|
||||||
|
result = 31 * result + (format != null ? format.hashCode() : 0);
|
||||||
|
result = 31 * result + (color != null ? color.hashCode() : 0);
|
||||||
|
result = 31 * result + (notify != null ? notify.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return toXContent(builder, params, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params, boolean includeTargets) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
if (from != null) {
|
||||||
|
builder.field(Field.FROM.getPreferredName(), from);
|
||||||
|
}
|
||||||
|
if (includeTargets) {
|
||||||
|
if (rooms != null && rooms.length > 0) {
|
||||||
|
builder.array(Field.ROOM.getPreferredName(), rooms);
|
||||||
|
}
|
||||||
|
if (users != null && users.length > 0) {
|
||||||
|
builder.array(Field.USER.getPreferredName(), users);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.field(Field.BODY.getPreferredName(), body);
|
||||||
|
if (format != null) {
|
||||||
|
builder.field(Field.FORMAT.getPreferredName(), format, params);
|
||||||
|
}
|
||||||
|
if (color != null) {
|
||||||
|
builder.field(Field.COLOR.getPreferredName(), color, params);
|
||||||
|
}
|
||||||
|
if (notify != null) {
|
||||||
|
builder.field(Field.NOTIFY.getPreferredName(), notify);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Template implements ToXContent {
|
||||||
|
|
||||||
|
final org.elasticsearch.watcher.support.template.Template body;
|
||||||
|
final @Nullable org.elasticsearch.watcher.support.template.Template[] rooms;
|
||||||
|
final @Nullable org.elasticsearch.watcher.support.template.Template[] users;
|
||||||
|
final @Nullable String from;
|
||||||
|
final @Nullable Format format;
|
||||||
|
final @Nullable org.elasticsearch.watcher.support.template.Template color;
|
||||||
|
final @Nullable Boolean notify;
|
||||||
|
|
||||||
|
public Template(org.elasticsearch.watcher.support.template.Template body,
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] rooms,
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] users,
|
||||||
|
String from,
|
||||||
|
Format format,
|
||||||
|
org.elasticsearch.watcher.support.template.Template color,
|
||||||
|
Boolean notify) {
|
||||||
|
this.rooms = rooms;
|
||||||
|
this.users = users;
|
||||||
|
this.body = body;
|
||||||
|
this.from = from;
|
||||||
|
this.format = format;
|
||||||
|
this.color = color;
|
||||||
|
this.notify = notify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Template template = (Template) o;
|
||||||
|
|
||||||
|
if (!body.equals(template.body)) return false;
|
||||||
|
if (!Arrays.equals(rooms, template.rooms)) return false;
|
||||||
|
if (!Arrays.equals(users, template.users)) return false;
|
||||||
|
if (from != null ? !from.equals(template.from) : template.from != null) return false;
|
||||||
|
if (format != template.format) return false;
|
||||||
|
if (color != null ? !color.equals(template.color) : template.color != null) return false;
|
||||||
|
return !(notify != null ? !notify.equals(template.notify) : template.notify != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = body.hashCode();
|
||||||
|
result = 31 * result + (rooms != null ? Arrays.hashCode(rooms) : 0);
|
||||||
|
result = 31 * result + (users != null ? Arrays.hashCode(users) : 0);
|
||||||
|
result = 31 * result + (from != null ? from.hashCode() : 0);
|
||||||
|
result = 31 * result + (format != null ? format.hashCode() : 0);
|
||||||
|
result = 31 * result + (color != null ? color.hashCode() : 0);
|
||||||
|
result = 31 * result + (notify != null ? notify.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatMessage render(TemplateEngine engine, Map<String, Object> model) {
|
||||||
|
String body = engine.render(this.body, model);
|
||||||
|
String[] rooms = null;
|
||||||
|
if (this.rooms != null) {
|
||||||
|
rooms = new String[this.rooms.length];
|
||||||
|
for (int i = 0; i < this.rooms.length; i++) {
|
||||||
|
rooms[i] = engine.render(this.rooms[i], model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] users = null;
|
||||||
|
if (this.users != null) {
|
||||||
|
users = new String[this.users.length];
|
||||||
|
for (int i = 0; i < this.users.length; i++) {
|
||||||
|
users[i] = engine.render(this.users[i], model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Color color = this.color == null ? null : Color.resolve(engine.render(this.color, model), null);
|
||||||
|
return new HipChatMessage(body, rooms, users, from, format, color, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
if (from != null) {
|
||||||
|
builder.field(Field.FROM.getPreferredName(), from);
|
||||||
|
}
|
||||||
|
if (rooms != null && rooms.length > 0) {
|
||||||
|
builder.startArray(Field.ROOM.getPreferredName());
|
||||||
|
for (org.elasticsearch.watcher.support.template.Template room : rooms) {
|
||||||
|
room.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
builder.endArray();
|
||||||
|
}
|
||||||
|
if (users != null && users.length > 0) {
|
||||||
|
builder.startArray(Field.USER.getPreferredName());
|
||||||
|
for (org.elasticsearch.watcher.support.template.Template user : users) {
|
||||||
|
user.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
builder.endArray();
|
||||||
|
}
|
||||||
|
builder.field(Field.BODY.getPreferredName(), body, params);
|
||||||
|
if (format != null) {
|
||||||
|
builder.field(Field.FORMAT.getPreferredName(), format, params);
|
||||||
|
}
|
||||||
|
if (color != null) {
|
||||||
|
builder.field(Field.COLOR.getPreferredName(), color, params);
|
||||||
|
}
|
||||||
|
if (notify != null) {
|
||||||
|
builder.field(Field.NOTIFY.getPreferredName(), notify);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Template parse(XContentParser parser) throws IOException {
|
||||||
|
org.elasticsearch.watcher.support.template.Template body = null;
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] rooms = null;
|
||||||
|
org.elasticsearch.watcher.support.template.Template[] users = null;
|
||||||
|
String from = null;
|
||||||
|
org.elasticsearch.watcher.support.template.Template color = null;
|
||||||
|
Boolean notify = null;
|
||||||
|
HipChatMessage.Format messageFormat = null;
|
||||||
|
|
||||||
|
String currentFieldName = null;
|
||||||
|
XContentParser.Token token;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.FROM)) {
|
||||||
|
from = parser.text();
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.ROOM)) {
|
||||||
|
List<org.elasticsearch.watcher.support.template.Template> templates = new ArrayList<>();
|
||||||
|
if (token == XContentParser.Token.START_ARRAY) {
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
|
try {
|
||||||
|
templates.add(org.elasticsearch.watcher.support.template.Template.parse(parser));
|
||||||
|
} catch (ElasticsearchParseException epe) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", epe, Field.ROOM.getPreferredName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
templates.add(org.elasticsearch.watcher.support.template.Template.parse(parser));
|
||||||
|
} catch (ElasticsearchParseException epe) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", epe, Field.ROOM.getPreferredName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rooms = templates.toArray(new org.elasticsearch.watcher.support.template.Template[templates.size()]);
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.USER)) {
|
||||||
|
List<org.elasticsearch.watcher.support.template.Template> templates = new ArrayList<>();
|
||||||
|
if (token == XContentParser.Token.START_ARRAY) {
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
|
try {
|
||||||
|
templates.add(org.elasticsearch.watcher.support.template.Template.parse(parser));
|
||||||
|
} catch (ElasticsearchParseException epe) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", epe, Field.USER.getPreferredName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
templates.add(org.elasticsearch.watcher.support.template.Template.parse(parser));
|
||||||
|
} catch (ElasticsearchParseException epe) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", epe, Field.USER.getPreferredName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
users = templates.toArray(new org.elasticsearch.watcher.support.template.Template[templates.size()]);
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.COLOR)) {
|
||||||
|
try {
|
||||||
|
color = org.elasticsearch.watcher.support.template.Template.parse(parser);
|
||||||
|
} catch (ElasticsearchParseException | IllegalArgumentException e) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", e, Field.COLOR.getPreferredName());
|
||||||
|
}
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.NOTIFY)) {
|
||||||
|
if (token == XContentParser.Token.VALUE_BOOLEAN) {
|
||||||
|
notify = parser.booleanValue();
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field, expected a boolean value but found [{}]", Field.NOTIFY.getPreferredName(), token);
|
||||||
|
}
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.BODY)) {
|
||||||
|
try {
|
||||||
|
body = org.elasticsearch.watcher.support.template.Template.parse(parser);
|
||||||
|
} catch (ElasticsearchParseException pe) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", pe, Field.BODY.getPreferredName());
|
||||||
|
}
|
||||||
|
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.FORMAT)) {
|
||||||
|
try {
|
||||||
|
messageFormat = HipChatMessage.Format.parse(parser);
|
||||||
|
} catch (IllegalArgumentException ilae) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", ilae, Field.FORMAT.getPreferredName());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. unexpected token [{}]", token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body == null) {
|
||||||
|
throw new ElasticsearchParseException("failed to parse hipchat message. missing required [{}] field", Field.BODY.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HipChatMessage.Template(body, rooms, users, from, messageFormat, color, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
final org.elasticsearch.watcher.support.template.Template body;
|
||||||
|
final List<org.elasticsearch.watcher.support.template.Template> rooms = new ArrayList<>();
|
||||||
|
final List<org.elasticsearch.watcher.support.template.Template> users = new ArrayList<>();
|
||||||
|
@Nullable String from;
|
||||||
|
@Nullable Format format;
|
||||||
|
@Nullable org.elasticsearch.watcher.support.template.Template color;
|
||||||
|
@Nullable Boolean notify;
|
||||||
|
|
||||||
|
public Builder(org.elasticsearch.watcher.support.template.Template body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addRooms(org.elasticsearch.watcher.support.template.Template... rooms) {
|
||||||
|
this.rooms.addAll(Arrays.asList(rooms));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder addUsers(org.elasticsearch.watcher.support.template.Template... users) {
|
||||||
|
this.users.addAll(Arrays.asList(users));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFrom(String from) {
|
||||||
|
this.from = from;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setFormat(Format format) {
|
||||||
|
this.format = format;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setColor(org.elasticsearch.watcher.support.template.Template color) {
|
||||||
|
this.color = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setNotify(boolean notify) {
|
||||||
|
this.notify = notify;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Template build() {
|
||||||
|
return new Template(
|
||||||
|
body,
|
||||||
|
rooms.isEmpty() ? null : rooms.toArray(new org.elasticsearch.watcher.support.template.Template[rooms.size()]),
|
||||||
|
users.isEmpty() ? null : users.toArray(new org.elasticsearch.watcher.support.template.Template[users.size()]),
|
||||||
|
from,
|
||||||
|
format,
|
||||||
|
color,
|
||||||
|
notify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum Color implements ToXContent {
|
||||||
|
YELLOW, GREEN, RED, PURPLE, GRAY, RANDOM;
|
||||||
|
|
||||||
|
private final org.elasticsearch.watcher.support.template.Template template = org.elasticsearch.watcher.support.template.Template.inline(name()).build();
|
||||||
|
|
||||||
|
public org.elasticsearch.watcher.support.template.Template asTemplate() {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.value(name().toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String value() {
|
||||||
|
return name().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color parse(XContentParser parser) throws IOException {
|
||||||
|
return Color.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color resolve(String value, Color defaultValue) {
|
||||||
|
if (value == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return Color.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color resolve(Settings settings, String setting, Color defaultValue) {
|
||||||
|
return resolve(settings.get(setting), defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validate(String value) {
|
||||||
|
try {
|
||||||
|
Color.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
return true;
|
||||||
|
} catch (IllegalArgumentException ilae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum Format implements ToXContent {
|
||||||
|
|
||||||
|
TEXT,
|
||||||
|
HTML;
|
||||||
|
|
||||||
|
private final org.elasticsearch.watcher.support.template.Template template = org.elasticsearch.watcher.support.template.Template.inline(name()).build();
|
||||||
|
|
||||||
|
public org.elasticsearch.watcher.support.template.Template asTemplate() {
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.value(name().toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String value() {
|
||||||
|
return name().toLowerCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format parse(XContentParser parser) throws IOException {
|
||||||
|
return Format.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format resolve(String value, Format defaultValue) {
|
||||||
|
if (value == null) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return Format.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Format resolve(Settings settings, String setting, Format defaultValue) {
|
||||||
|
return resolve(settings.get(setting), defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validate(String value) {
|
||||||
|
try {
|
||||||
|
Format.valueOf(value.toUpperCase(Locale.ROOT));
|
||||||
|
return true;
|
||||||
|
} catch (IllegalArgumentException ilae) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Field {
|
||||||
|
ParseField ROOM = new ParseField("room");
|
||||||
|
ParseField USER = new ParseField("user");
|
||||||
|
ParseField BODY = new ParseField("body");
|
||||||
|
ParseField FROM = new ParseField("from");
|
||||||
|
ParseField COLOR = new ParseField("color");
|
||||||
|
ParseField NOTIFY = new ParseField("notify");
|
||||||
|
ParseField FORMAT = new ParseField("format");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatServer {
|
||||||
|
|
||||||
|
public static final String HOST_SETTING = "host";
|
||||||
|
public static final String PORT_SETTING = "port";
|
||||||
|
|
||||||
|
public static final HipChatServer DEFAULT = new HipChatServer("api.hipchat.com", 443, null);
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
private final HipChatServer fallback;
|
||||||
|
|
||||||
|
public HipChatServer(Settings settings) {
|
||||||
|
this(settings, DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatServer(Settings settings, HipChatServer fallback) {
|
||||||
|
this(settings.get(HOST_SETTING, null), settings.getAsInt(PORT_SETTING, -1), fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatServer(String host, int port, HipChatServer fallback) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.fallback = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String host() {
|
||||||
|
return host != null ? host : fallback.host();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int port() {
|
||||||
|
return port > 0 ? port : fallback.port();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatServer fallback() {
|
||||||
|
return fallback != null ? fallback : DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HipChatServer rebuild(Settings settings, HipChatServer fallback) {
|
||||||
|
return new HipChatServer(settings.get(HOST_SETTING, host), settings.getAsInt(PORT_SETTING, port), fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized HttpRequest.Builder httpRequest() {
|
||||||
|
return HttpRequest.builder(host(), port());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface HipChatService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The default hipchat account.
|
||||||
|
*/
|
||||||
|
HipChatAccount getDefaultAccount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The account identified by the given name. If the given name is {@code null} the default
|
||||||
|
* account will be returned.
|
||||||
|
*/
|
||||||
|
HipChatAccount getAccount(String accountName);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Color;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Format;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class IntegrationAccount extends HipChatAccount {
|
||||||
|
|
||||||
|
public static final String TYPE = "integration";
|
||||||
|
|
||||||
|
final String room;
|
||||||
|
final Defaults defaults;
|
||||||
|
|
||||||
|
public IntegrationAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
super(name, Profile.INTEGRATION, settings, defaultServer, httpClient, logger);
|
||||||
|
String[] rooms = settings.getAsArray(ROOM_SETTING, null);
|
||||||
|
if (rooms == null || rooms.length == 0) {
|
||||||
|
throw new SettingsException("invalid hipchat account [" + name + "]. missing required [" + ROOM_SETTING + "] setting for [" + TYPE + "] account profile");
|
||||||
|
}
|
||||||
|
if (rooms.length > 1) {
|
||||||
|
throw new SettingsException("invalid hipchat account [" + name + "]. [" + ROOM_SETTING + "] setting for [" + TYPE + "] account must only be set with a single value");
|
||||||
|
}
|
||||||
|
this.room = rooms[0];
|
||||||
|
defaults = new Defaults(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateParsedTemplate(String watchId, String actionId, HipChatMessage.Template template) throws SettingsException {
|
||||||
|
if (template.rooms != null) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "] action. [" + name + "] hipchat account doesn't support custom rooms");
|
||||||
|
}
|
||||||
|
if (template.users != null) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "] action. [" + name + "] hipchat account doesn't support user private messages");
|
||||||
|
}
|
||||||
|
if (template.from != null) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "] action. [" + name + "] hipchat account doesn't support custom `from` fields");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatMessage render(String watchId, String actionId, TemplateEngine engine, HipChatMessage.Template template, Map<String, Object> model) {
|
||||||
|
String message = engine.render(template.body, model);
|
||||||
|
Color color = template.color != null ? Color.resolve(engine.render(template.color, model), defaults.color) : defaults.color;
|
||||||
|
Boolean notify = template.notify != null ? template.notify : defaults.notify;
|
||||||
|
Format messageFormat = template.format != null ? template.format : defaults.format;
|
||||||
|
return new HipChatMessage(message, null, null, null, messageFormat, color, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SentMessages send(HipChatMessage message) {
|
||||||
|
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
|
||||||
|
HttpRequest request = buildRoomRequest(room, message);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.responded(room, SentMessages.SentMessage.TargetType.ROOM, message, request, response));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("failed to execute hipchat api http request", e);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.error(room, SentMessages.SentMessage.TargetType.ROOM, message, ExceptionsHelper.detailedMessage(e)));
|
||||||
|
}
|
||||||
|
return new SentMessages(name, sentMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest buildRoomRequest(String room, final HipChatMessage message) {
|
||||||
|
return server.httpRequest()
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/room/" + room + "/notification")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer " + authToken)
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder xbuilder, Params params) throws IOException {
|
||||||
|
xbuilder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
xbuilder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
xbuilder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
xbuilder.field("color", String.valueOf(message.color.value()));
|
||||||
|
}
|
||||||
|
return xbuilder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Defaults {
|
||||||
|
|
||||||
|
final @Nullable Format format;
|
||||||
|
final @Nullable Color color;
|
||||||
|
final @Nullable Boolean notify;
|
||||||
|
|
||||||
|
public Defaults(Settings settings) {
|
||||||
|
this.format = Format.resolve(settings, DEFAULT_FORMAT_SETTING, null);
|
||||||
|
this.color = Color.resolve(settings, DEFAULT_COLOR_SETTING, null);
|
||||||
|
this.notify = settings.getAsBoolean(DEFAULT_NOTIFY_SETTING, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.component.AbstractLifecycleComponent;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.node.settings.NodeSettingsService;
|
||||||
|
import org.elasticsearch.watcher.shield.WatcherSettingsFilter;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InternalHipChatService extends AbstractLifecycleComponent<InternalHipChatService> implements HipChatService {
|
||||||
|
|
||||||
|
private final HttpClient httpClient;
|
||||||
|
private volatile HipChatAccounts accounts;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public InternalHipChatService(Settings settings, HttpClient httpClient, NodeSettingsService nodeSettingsService, WatcherSettingsFilter settingsFilter) {
|
||||||
|
super(settings);
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
nodeSettingsService.addListener(new NodeSettingsService.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onRefreshSettings(Settings settings) {
|
||||||
|
reset(settings);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
settingsFilter.filterOut("watcher.actions.hipchat.service.account.*.auth_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStart() {
|
||||||
|
reset(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStop() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doClose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatAccount getDefaultAccount() {
|
||||||
|
return accounts.account(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatAccount getAccount(String name) {
|
||||||
|
return accounts.account(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(Settings nodeSettings) {
|
||||||
|
Settings.Builder builder = Settings.builder();
|
||||||
|
String prefix = "watcher.actions.hipchat.service";
|
||||||
|
for (String setting : settings.getAsMap().keySet()) {
|
||||||
|
if (setting.startsWith(prefix)) {
|
||||||
|
builder.put(setting.substring(prefix.length()+1), settings.get(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nodeSettings != settings) { // if it's the same settings, no point in re-applying it
|
||||||
|
for (String setting : nodeSettings.getAsMap().keySet()) {
|
||||||
|
if (setting.startsWith(prefix)) {
|
||||||
|
builder.put(setting.substring(prefix.length() + 1), nodeSettings.get(setting));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilderString;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpRequest;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpResponse;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SentMessages implements ToXContent, Iterable<SentMessages.SentMessage> {
|
||||||
|
|
||||||
|
private String accountName;
|
||||||
|
private List<SentMessage> messages;
|
||||||
|
|
||||||
|
public SentMessages(String accountName, List<SentMessage> messages) {
|
||||||
|
this.accountName = accountName;
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccountName() {
|
||||||
|
return accountName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<SentMessage> iterator() {
|
||||||
|
return messages.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return messages.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SentMessage> asList() {
|
||||||
|
return Collections.unmodifiableList(messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Field.ACCOUNT, accountName);
|
||||||
|
builder.startArray(Field.SENT_MESSAGES);
|
||||||
|
for (SentMessage message : messages) {
|
||||||
|
message.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
builder.endArray();
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SentMessage implements ToXContent {
|
||||||
|
|
||||||
|
public enum TargetType {
|
||||||
|
ROOM, USER;
|
||||||
|
|
||||||
|
final XContentBuilderString fieldName = new XContentBuilderString(name().toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
final String targetName;
|
||||||
|
final TargetType targetType;
|
||||||
|
final HipChatMessage message;
|
||||||
|
final @Nullable HttpRequest request;
|
||||||
|
final @Nullable HttpResponse response;
|
||||||
|
final @Nullable String failureReason;
|
||||||
|
|
||||||
|
public static SentMessage responded(String targetName, TargetType targetType, HipChatMessage message, HttpRequest request, HttpResponse response) {
|
||||||
|
String failureReason = resolveFailureReason(response);
|
||||||
|
return new SentMessage(targetName, targetType, message, request, response, failureReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SentMessage error(String targetName, TargetType targetType, HipChatMessage message, String reason) {
|
||||||
|
return new SentMessage(targetName, targetType, message, null, null, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SentMessage(String targetName, TargetType targetType, HipChatMessage message, HttpRequest request, HttpResponse response, String failureReason) {
|
||||||
|
this.targetName = targetName;
|
||||||
|
this.targetType = targetType;
|
||||||
|
this.message = message;
|
||||||
|
this.request = request;
|
||||||
|
this.response = response;
|
||||||
|
this.failureReason = failureReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean successful() {
|
||||||
|
return failureReason == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
if (failureReason != null) {
|
||||||
|
builder.field(Field.STATUS, "failure");
|
||||||
|
builder.field(Field.REASON, failureReason);
|
||||||
|
if (request != null) {
|
||||||
|
builder.field(Field.REQUEST);
|
||||||
|
request.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
builder.field(Field.RESPONSE);
|
||||||
|
response.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.field(Field.STATUS, "success");
|
||||||
|
}
|
||||||
|
builder.field(targetType.fieldName, targetName);
|
||||||
|
builder.field(Field.MESSAGE);
|
||||||
|
message.toXContent(builder, params, false);
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String resolveFailureReason(HttpResponse response) {
|
||||||
|
int status = response.status();
|
||||||
|
if (status < 300) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
switch (status) {
|
||||||
|
case 400: return "Bad Request";
|
||||||
|
case 401: return "Unauthorized. The provided authentication token is invalid.";
|
||||||
|
case 403: return "Forbidden. The account doesn't have permission to send this message.";
|
||||||
|
case 404: // Not Found
|
||||||
|
case 405: // Method Not Allowed
|
||||||
|
case 406: return "The account used invalid HipChat APIs"; // Not Acceptable
|
||||||
|
case 503:
|
||||||
|
case 500: return "HipChat Server Error.";
|
||||||
|
default:
|
||||||
|
return "Unknown Error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Field {
|
||||||
|
XContentBuilderString ACCOUNT = new XContentBuilderString("account");
|
||||||
|
XContentBuilderString SENT_MESSAGES = new XContentBuilderString("sent_messages");
|
||||||
|
XContentBuilderString STATUS = new XContentBuilderString("status");
|
||||||
|
XContentBuilderString REASON = new XContentBuilderString("reason");
|
||||||
|
XContentBuilderString REQUEST = new XContentBuilderString("request");
|
||||||
|
XContentBuilderString RESPONSE = new XContentBuilderString("response");
|
||||||
|
XContentBuilderString MESSAGE = new XContentBuilderString("message");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Color;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Format;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class UserAccount extends HipChatAccount {
|
||||||
|
|
||||||
|
public static final String TYPE = "user";
|
||||||
|
|
||||||
|
final Defaults defaults;
|
||||||
|
|
||||||
|
public UserAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
super(name, Profile.USER, settings, defaultServer, httpClient, logger);
|
||||||
|
defaults = new Defaults(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateParsedTemplate(String watchId, String actionId, HipChatMessage.Template template) throws SettingsException {
|
||||||
|
if (template.from != null) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "]. [" + name + "] hipchat account doesn't support custom `from` fields");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatMessage render(String watchId, String actionId, TemplateEngine engine, HipChatMessage.Template template, Map<String, Object> model) {
|
||||||
|
String[] rooms = defaults.rooms;
|
||||||
|
if (template.rooms != null) {
|
||||||
|
rooms = new String[template.rooms.length];
|
||||||
|
for (int i = 0; i < template.rooms.length; i++) {
|
||||||
|
rooms[i] = engine.render(template.rooms[i], model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String[] users = defaults.users;
|
||||||
|
if (template.users != null) {
|
||||||
|
users = new String[template.users.length];
|
||||||
|
for (int i = 0; i < template.users.length; i++) {
|
||||||
|
users[i] = engine.render(template.users[i], model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String message = engine.render(template.body, model);
|
||||||
|
Color color = Color.resolve(engine.render(template.color, model), defaults.color);
|
||||||
|
Boolean notify = template.notify != null ? template.notify : defaults.notify;
|
||||||
|
Format messageFormat = template.format != null ? template.format : defaults.format;
|
||||||
|
return new HipChatMessage(message, rooms, users, null, messageFormat, color, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SentMessages send(HipChatMessage message) {
|
||||||
|
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
|
||||||
|
if (message.rooms != null) {
|
||||||
|
for (String room : message.rooms) {
|
||||||
|
HttpRequest request = buildRoomRequest(room, message);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.responded(room, SentMessages.SentMessage.TargetType.ROOM, message, request, response));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("failed to execute hipchat api http request", e);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.error(room, SentMessages.SentMessage.TargetType.ROOM, message, ExceptionsHelper.detailedMessage(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.users != null) {
|
||||||
|
for (String user : message.users) {
|
||||||
|
HttpRequest request = buildUserRequest(user, message);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.responded(user, SentMessages.SentMessage.TargetType.USER, message, request, response));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("failed to execute hipchat api http request", e);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.error(user, SentMessages.SentMessage.TargetType.USER, message, ExceptionsHelper.detailedMessage(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SentMessages(name, sentMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest buildRoomRequest(String room, final HipChatMessage message) {
|
||||||
|
return server.httpRequest()
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/room/" + room + "/notification")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer " + authToken)
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder xbuilder, Params params) throws IOException {
|
||||||
|
xbuilder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
xbuilder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
xbuilder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
xbuilder.field("color", String.valueOf(message.color.value()));
|
||||||
|
}
|
||||||
|
return xbuilder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest buildUserRequest(String user, final HipChatMessage message) {
|
||||||
|
return server.httpRequest()
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/user/" + user + "/message")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer " + authToken)
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder xbuilder, Params params) throws IOException {
|
||||||
|
xbuilder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
xbuilder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
xbuilder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
return xbuilder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Defaults {
|
||||||
|
|
||||||
|
final @Nullable String[] rooms;
|
||||||
|
final @Nullable String[] users;
|
||||||
|
final @Nullable Format format;
|
||||||
|
final @Nullable Color color;
|
||||||
|
final @Nullable Boolean notify;
|
||||||
|
|
||||||
|
public Defaults(Settings settings) {
|
||||||
|
this.rooms = settings.getAsArray(DEFAULT_ROOM_SETTING, null);
|
||||||
|
this.users = settings.getAsArray(DEFAULT_USER_SETTING, null);
|
||||||
|
this.format = Format.resolve(settings, DEFAULT_FORMAT_SETTING, null);
|
||||||
|
this.color = Color.resolve(settings, DEFAULT_COLOR_SETTING, null);
|
||||||
|
this.notify = settings.getAsBoolean(DEFAULT_NOTIFY_SETTING, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Color;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage.Format;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class V1Account extends HipChatAccount {
|
||||||
|
|
||||||
|
public static final String TYPE = "v1";
|
||||||
|
|
||||||
|
final Defaults defaults;
|
||||||
|
|
||||||
|
public V1Account(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient, ESLogger logger) {
|
||||||
|
super(name, Profile.V1, settings, defaultServer, httpClient, logger);
|
||||||
|
defaults = new Defaults(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateParsedTemplate(String watchId, String actionId, HipChatMessage.Template template) throws ElasticsearchParseException {
|
||||||
|
if (template.users != null) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "]. [" + name + "] hipchat account doesn't support user private messaging");
|
||||||
|
}
|
||||||
|
if ((template.rooms == null || template.rooms.length == 0) && (defaults.rooms == null || defaults.rooms.length == 0)) {
|
||||||
|
throw new ElasticsearchParseException("invalid [" + HipChatAction.TYPE + "] action for [" + watchId + "/" + actionId + "]. missing required [" + HipChatMessage.Field.ROOM + "] field for [" + name + "] hipchat account");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HipChatMessage render(String watchId, String actionId, TemplateEngine engine, HipChatMessage.Template template, Map<String, Object> model) {
|
||||||
|
String message = engine.render(template.body, model);
|
||||||
|
String[] rooms = defaults.rooms;
|
||||||
|
if (template.rooms != null) {
|
||||||
|
rooms = new String[template.rooms.length];
|
||||||
|
for (int i = 0; i < template.rooms.length; i++) {
|
||||||
|
rooms[i] = engine.render(template.rooms[i], model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String from = template.from != null ? template.from : defaults.from != null ? defaults.from : watchId;
|
||||||
|
Color color = Color.resolve(engine.render(template.color, model), defaults.color);
|
||||||
|
Boolean notify = template.notify != null ? template.notify : defaults.notify;
|
||||||
|
Format messageFormat = template.format != null ? template.format : defaults.format;
|
||||||
|
return new HipChatMessage(message, rooms, null, from, messageFormat, color, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SentMessages send(HipChatMessage message) {
|
||||||
|
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
|
||||||
|
if (message.rooms != null) {
|
||||||
|
for (String room : message.rooms) {
|
||||||
|
HttpRequest request = buildRoomRequest(room, message);
|
||||||
|
try {
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.responded(room, SentMessages.SentMessage.TargetType.ROOM, message, request, response));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("failed to execute hipchat api http request", e);
|
||||||
|
sentMessages.add(SentMessages.SentMessage.error(room, SentMessages.SentMessage.TargetType.ROOM, message, ExceptionsHelper.detailedMessage(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new SentMessages(name, sentMessages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest buildRoomRequest(String room, HipChatMessage message) {
|
||||||
|
HttpRequest.Builder builder = server.httpRequest();
|
||||||
|
builder.method(HttpMethod.POST);
|
||||||
|
builder.scheme(Scheme.HTTPS);
|
||||||
|
builder.path("/v1/rooms/message");
|
||||||
|
builder.setHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
builder.setParam("format", "json");
|
||||||
|
builder.setParam("auth_token", authToken);
|
||||||
|
|
||||||
|
StringBuilder body = new StringBuilder();
|
||||||
|
body.append("room_id=").append(room);
|
||||||
|
body.append("&from=").append(HttpRequest.encodeUrl(message.from));
|
||||||
|
body.append("&message=").append(HttpRequest.encodeUrl(message.body));
|
||||||
|
if (message.format != null) {
|
||||||
|
body.append("&message_format=").append(message.format.value());
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
body.append("&color=").append(message.color.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
body.append("¬ify=").append(message.notify ? "1" : "0");
|
||||||
|
}
|
||||||
|
builder.body(body.toString());
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Defaults {
|
||||||
|
|
||||||
|
final @Nullable String[] rooms;
|
||||||
|
final @Nullable String from;
|
||||||
|
final @Nullable Format format;
|
||||||
|
final @Nullable Color color;
|
||||||
|
final @Nullable Boolean notify;
|
||||||
|
|
||||||
|
public Defaults(Settings settings) {
|
||||||
|
this.rooms = settings.getAsArray(DEFAULT_ROOM_SETTING, null);
|
||||||
|
this.from = settings.get(DEFAULT_FROM_SETTING);
|
||||||
|
this.format = Format.resolve(settings, DEFAULT_FORMAT_SETTING, null);
|
||||||
|
this.color = Color.resolve(settings, DEFAULT_COLOR_SETTING, null);
|
||||||
|
this.notify = settings.getAsBoolean(DEFAULT_NOTIFY_SETTING, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,9 @@ import org.elasticsearch.watcher.support.http.auth.HttpAuth;
|
||||||
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class HttpRequest implements ToXContent {
|
public class HttpRequest implements ToXContent {
|
||||||
|
@ -101,6 +104,22 @@ public class HttpRequest implements ToXContent {
|
||||||
return readTimeout;
|
return readTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String encodeUrl(String text) {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(text, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new IllegalArgumentException("failed to URL encode text [" + text + "]", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String decodeUrl(String text) {
|
||||||
|
try {
|
||||||
|
return URLDecoder.decode(text, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new IllegalArgumentException("failed to URL decode text [" + text + "]", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
|
@ -171,16 +190,28 @@ public class HttpRequest implements ToXContent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "HttpRequest{" +
|
StringBuilder sb = new StringBuilder();
|
||||||
"auth=[" + (auth != null ? "******" : null) +
|
sb.append("method=[").append(method).append("], ");
|
||||||
"], body=[" + body + '\'' +
|
sb.append("scheme=[").append(scheme).append("], ");
|
||||||
"], path=[" + path + '\'' +
|
sb.append("host=[").append(host).append("], ");
|
||||||
"], method=[" + method +
|
sb.append("port=[").append(port).append("], ");
|
||||||
"], port=[" + port +
|
sb.append("path=[").append(path).append("], ");
|
||||||
"], host=[" + host + '\'' +
|
if (!headers.isEmpty()) {
|
||||||
"], connection_timeout=[" + connectionTimeout + '\'' +
|
sb.append(", headers=[");
|
||||||
"], read_timeout=[" + readTimeout + '\'' +
|
boolean first = true;
|
||||||
"]}";
|
for (Map.Entry<String, String> header : headers.entrySet()) {
|
||||||
|
if (!first) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append("[").append(header.getKey()).append(": ").append(header.getValue()).append("]");
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
sb.append("], ");
|
||||||
|
}
|
||||||
|
sb.append("connection_timeout=[").append(connectionTimeout).append("], ");
|
||||||
|
sb.append("read_timeout=[").append(readTimeout).append("], ");
|
||||||
|
sb.append("body=[").append(body).append("], ");
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Builder builder(String host, int port) {
|
public static Builder builder(String host, int port) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import org.jboss.netty.handler.codec.http.HttpHeaders;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -111,6 +112,28 @@ public class HttpResponse implements ToXContent {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("status=[").append(status).append("]");
|
||||||
|
if (!headers.isEmpty()) {
|
||||||
|
sb.append(", headers=[");
|
||||||
|
boolean first = true;
|
||||||
|
for (Map.Entry<String, String[]> header : headers.entrySet()) {
|
||||||
|
if (!first) {
|
||||||
|
sb.append(", ");
|
||||||
|
}
|
||||||
|
sb.append("[").append(header.getKey()).append(": ").append(Arrays.toString(header.getValue())).append("]");
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
sb.append("]");
|
||||||
|
}
|
||||||
|
if (hasContent()) {
|
||||||
|
sb.append(", body=[").append(body.toUtf8()).append("]");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder = builder.startObject().field(Field.STATUS.getPreferredName(), status);
|
builder = builder.startObject().field(Field.STATUS.getPreferredName(), status);
|
||||||
|
|
|
@ -8,11 +8,6 @@ package org.elasticsearch.watcher.support.xcontent;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.compress.CompressedStreamInput;
|
|
||||||
import org.elasticsearch.common.compress.Compressor;
|
|
||||||
import org.elasticsearch.common.compress.CompressorFactory;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
@ -38,6 +33,29 @@ public class WatcherXContentUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String[] readStringArray(XContentParser parser, boolean allowNull) throws IOException {
|
||||||
|
if (parser.currentToken() == XContentParser.Token.VALUE_NULL) {
|
||||||
|
if (allowNull) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw new ElasticsearchParseException("could not parse [{}] field. expected a string array but found null value instead", parser.currentName());
|
||||||
|
}
|
||||||
|
if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
|
||||||
|
throw new ElasticsearchParseException("could not parse [{}] field. expected a string array but found [{}] value instead", parser.currentName(), parser.currentToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
XContentParser.Token token;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||||
|
if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
list.add(parser.text());
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse [{}] field. expected a string array but one of the value in the array is [{}]", parser.currentName(), token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.toArray(new String[list.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO open this up in core
|
// TODO open this up in core
|
||||||
public static List<Object> readList(XContentParser parser, XContentParser.Token token) throws IOException {
|
public static List<Object> readList(XContentParser parser, XContentParser.Token token) throws IOException {
|
||||||
List<Object> list = new ArrayList<>();
|
List<Object> list = new ArrayList<>();
|
||||||
|
|
|
@ -321,6 +321,69 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"hipchat" : {
|
||||||
|
"type": "object",
|
||||||
|
"dynamic": true,
|
||||||
|
"properties": {
|
||||||
|
"account": {
|
||||||
|
"type": "string",
|
||||||
|
"index": "not_analyzed"
|
||||||
|
},
|
||||||
|
"sent_messages": {
|
||||||
|
"type": "nested",
|
||||||
|
"include_in_parent": true,
|
||||||
|
"dynamic": true,
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"index": "not_analyzed"
|
||||||
|
},
|
||||||
|
"reason": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"request" : {
|
||||||
|
"type" : "object",
|
||||||
|
"enabled" : false
|
||||||
|
},
|
||||||
|
"response" : {
|
||||||
|
"type" : "object",
|
||||||
|
"enabled" : false
|
||||||
|
},
|
||||||
|
"room" : {
|
||||||
|
"type": "string",
|
||||||
|
"index": "not_analyzed"
|
||||||
|
},
|
||||||
|
"user" : {
|
||||||
|
"type": "string",
|
||||||
|
"index": "not_analyzed"
|
||||||
|
},
|
||||||
|
"message" : {
|
||||||
|
"type" : "object",
|
||||||
|
"dynamic" : true,
|
||||||
|
"properties" : {
|
||||||
|
"message_format" : {
|
||||||
|
"type" : "string",
|
||||||
|
"index" : "not_analyzed"
|
||||||
|
},
|
||||||
|
"color" : {
|
||||||
|
"type" : "string",
|
||||||
|
"index" : "not_analyzed"
|
||||||
|
},
|
||||||
|
"notify" : {
|
||||||
|
"type" : "boolean"
|
||||||
|
},
|
||||||
|
"message" : {
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
"from" : {
|
||||||
|
"type" : "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,22 @@ public class WatcherF {
|
||||||
System.setProperty("es.shield.enabled", "false");
|
System.setProperty("es.shield.enabled", "false");
|
||||||
System.setProperty("es.security.manager.enabled", "false");
|
System.setProperty("es.security.manager.enabled", "false");
|
||||||
System.setProperty("es.plugins.load_classpath_plugins", "false");
|
System.setProperty("es.plugins.load_classpath_plugins", "false");
|
||||||
|
|
||||||
|
// this is for the `test-watcher-integration` group level integration in HipChat
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.integration.profile", "integration");
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.integration.auth_token", "huuS9v7ccuOy3ZBWWWr1vt8Lqu3sQnLUE81nrLZU");
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.integration.room", "test-watcher");
|
||||||
|
|
||||||
|
// this is for the Watcher Test account in HipChat
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.user.profile", "user");
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.user.auth_token", "FYVx16oDH78ZW9r13wtXbcszyoyA7oX5tiMWg9X0");
|
||||||
|
|
||||||
|
// this is for the `test-watcher-v1` notification token
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.v1.profile", "v1");
|
||||||
|
System.setProperty("es.watcher.actions.hipchat.service.account.v1.auth_token", "a734baf62df618b96dda55b323fc30");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
System.setProperty("es.plugin.types", WatcherPlugin.class.getName() + "," + LicensePlugin.class.getName());
|
System.setProperty("es.plugin.types", WatcherPlugin.class.getName() + "," + LicensePlugin.class.getName());
|
||||||
System.setProperty("es.cluster.name", WatcherF.class.getSimpleName());
|
System.setProperty("es.cluster.name", WatcherF.class.getSimpleName());
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatAccount;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatService;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.elasticsearch.watcher.actions.ActionBuilders.hipchatAction;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatActionFactoryTests extends ESTestCase {
|
||||||
|
|
||||||
|
private HipChatActionFactory factory;
|
||||||
|
private HipChatService hipchatService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
hipchatService = mock(HipChatService.class);
|
||||||
|
factory = new HipChatActionFactory(Settings.EMPTY, mock(TemplateEngine.class), hipchatService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseAction() throws Exception {
|
||||||
|
|
||||||
|
HipChatAccount account = mock(HipChatAccount.class);
|
||||||
|
when(hipchatService.getAccount("_account1")).thenReturn(account);
|
||||||
|
|
||||||
|
HipChatAction action = hipchatAction("_account1", "_body").build();
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder().value(action);
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatAction parsedAction = factory.parseAction("_w1", "_a1", parser);
|
||||||
|
assertThat(parsedAction, is(action));
|
||||||
|
|
||||||
|
verify(account, times(1)).validateParsedTemplate("_w1", "_a1", action.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ElasticsearchParseException.class)
|
||||||
|
public void testtestParseAction_UnknownAccount() throws Exception {
|
||||||
|
|
||||||
|
when(hipchatService.getAccount("_unknown")).thenReturn(null);
|
||||||
|
|
||||||
|
HipChatAction action = hipchatAction("_unknown", "_body").build();
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder().value(action);
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
factory.parseAction("_w1", "_a1", parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParser() throws Exception {
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
builder.field("account", accountName);
|
||||||
|
builder.startObject("message");
|
||||||
|
|
||||||
|
Template body = Template.inline("_body").build();
|
||||||
|
builder.field("body", body);
|
||||||
|
|
||||||
|
Template[] rooms = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template r1 = Template.inline("_r1").build();
|
||||||
|
Template r2 = Template.inline("_r2").build();
|
||||||
|
rooms = new Template[] { r1, r2 };
|
||||||
|
builder.array("room", r1, r2);
|
||||||
|
}
|
||||||
|
Template[] users = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template u1 = Template.inline("_u1").build();
|
||||||
|
Template u2 = Template.inline("_u2").build();
|
||||||
|
users = new Template[] { u1, u2 };
|
||||||
|
builder.array("user", u1, u2);
|
||||||
|
}
|
||||||
|
String from = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
from = randomAsciiOfLength(10);
|
||||||
|
builder.field("from", from);
|
||||||
|
}
|
||||||
|
HipChatMessage.Format format = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
builder.field("format", format.value());
|
||||||
|
}
|
||||||
|
Template color = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
color = Template.inline(randomFrom(HipChatMessage.Color.values()).value()).build();
|
||||||
|
builder.field("color", color);
|
||||||
|
}
|
||||||
|
Boolean notify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
notify = randomBoolean();
|
||||||
|
builder.field("notify", notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.endObject();
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
BytesReference bytes = builder.bytes();
|
||||||
|
logger.info("hipchat action json [{}]", bytes.toUtf8());
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatAction action = HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
|
||||||
|
assertThat(action, notNullValue());
|
||||||
|
assertThat(action.account, is(accountName));
|
||||||
|
assertThat(action.message, notNullValue());
|
||||||
|
assertThat(action.message, is(new HipChatMessage.Template(body, rooms, users, from, format, color, notify)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParser_SelfGenerated() throws Exception {
|
||||||
|
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
Template body = Template.inline("_body").build();
|
||||||
|
HipChatMessage.Template.Builder templateBuilder = new HipChatMessage.Template.Builder(body);
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
builder.field("account", accountName);
|
||||||
|
builder.startObject("message");
|
||||||
|
builder.field("body", body);
|
||||||
|
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template r1 = Template.inline("_r1").build();
|
||||||
|
Template r2 = Template.inline("_r2").build();
|
||||||
|
templateBuilder.addRooms(r1, r2);
|
||||||
|
builder.array("room", r1, r2);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template u1 = Template.inline("_u1").build();
|
||||||
|
Template u2 = Template.inline("_u2").build();
|
||||||
|
templateBuilder.addUsers(u1, u2);
|
||||||
|
builder.array("user", u1, u2);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
String from = randomAsciiOfLength(10);
|
||||||
|
templateBuilder.setFrom(from);
|
||||||
|
builder.field("from", from);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
HipChatMessage.Format format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
templateBuilder.setFormat(format);
|
||||||
|
builder.field("format", format.value());
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template color = Template.inline(randomFrom(HipChatMessage.Color.values()).value()).build();
|
||||||
|
templateBuilder.setColor(color);
|
||||||
|
builder.field("color", color);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
boolean notify = randomBoolean();
|
||||||
|
templateBuilder.setNotify(notify);
|
||||||
|
builder.field("notify", notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.endObject();
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
HipChatMessage.Template template = templateBuilder.build();
|
||||||
|
|
||||||
|
HipChatAction action = new HipChatAction(accountName, template);
|
||||||
|
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder();
|
||||||
|
action.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
BytesReference bytes = builder.bytes();
|
||||||
|
logger.info(bytes.toUtf8());
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatAction parsedAction = HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
|
||||||
|
assertThat(parsedAction, notNullValue());
|
||||||
|
assertThat(parsedAction, is(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ElasticsearchParseException.class)
|
||||||
|
public void testParser_Invalid() throws Exception {
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject().field("unknown_field", "value");
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.actions.Action;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatAccount;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatMessage;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.HipChatService;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.service.SentMessages;
|
||||||
|
import org.elasticsearch.watcher.execution.WatchExecutionContext;
|
||||||
|
import org.elasticsearch.watcher.execution.Wid;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpRequest;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpResponse;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.support.template.TemplateEngine;
|
||||||
|
import org.elasticsearch.watcher.watch.Payload;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.elasticsearch.watcher.test.WatcherTestUtils.mockExecutionContextBuilder;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatActionTests extends ESTestCase {
|
||||||
|
|
||||||
|
private HipChatService service;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
service = mock(HipChatService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecute() throws Exception {
|
||||||
|
final String accountName = "account1";
|
||||||
|
|
||||||
|
TemplateEngine templateEngine = mock(TemplateEngine.class);
|
||||||
|
|
||||||
|
Template body = Template.inline("_body").build();
|
||||||
|
HipChatMessage.Template.Builder messageBuilder = new HipChatMessage.Template.Builder(body);
|
||||||
|
|
||||||
|
HipChatMessage.Template messageTemplate = messageBuilder.build();
|
||||||
|
|
||||||
|
HipChatAction action = new HipChatAction(accountName, messageTemplate);
|
||||||
|
ExecutableHipChatAction executable = new ExecutableHipChatAction(action, logger, service, templateEngine);
|
||||||
|
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
Payload payload = new Payload.Simple(data);
|
||||||
|
|
||||||
|
Map<String, Object> metadata = MapBuilder.<String, Object>newMapBuilder().put("_key", "_val").map();
|
||||||
|
|
||||||
|
DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||||
|
|
||||||
|
Wid wid = new Wid(randomAsciiOfLength(5), randomLong(), now);
|
||||||
|
WatchExecutionContext ctx = mockExecutionContextBuilder(wid.watchId())
|
||||||
|
.wid(wid)
|
||||||
|
.payload(payload)
|
||||||
|
.time(wid.watchId(), now)
|
||||||
|
.metadata(metadata)
|
||||||
|
.buildMock();
|
||||||
|
|
||||||
|
Map<String, Object> expectedModel = ImmutableMap.<String, Object>builder()
|
||||||
|
.put("ctx", ImmutableMap.<String, Object>builder()
|
||||||
|
.put("id", ctx.id().value())
|
||||||
|
.put("watch_id", wid.watchId())
|
||||||
|
.put("payload", data)
|
||||||
|
.put("metadata", metadata)
|
||||||
|
.put("execution_time", now)
|
||||||
|
.put("trigger", ImmutableMap.<String, Object>builder()
|
||||||
|
.put("triggered_time", now)
|
||||||
|
.put("scheduled_time", now)
|
||||||
|
.build())
|
||||||
|
.put("vars", Collections.emptyMap())
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if (body != null) {
|
||||||
|
when(templateEngine.render(body, expectedModel)).thenReturn(body.getTemplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] rooms = new String[] { "_r1" };
|
||||||
|
HipChatMessage message = new HipChatMessage(body.getTemplate(), rooms, null, null, null, null, null);
|
||||||
|
HipChatAccount account = mock(HipChatAccount.class);
|
||||||
|
when(account.render(wid.watchId(), "_id", templateEngine, messageTemplate, expectedModel)).thenReturn(message);
|
||||||
|
HttpResponse response = mock(HttpResponse.class);
|
||||||
|
when(response.status()).thenReturn(200);
|
||||||
|
HttpRequest request = mock(HttpRequest.class);
|
||||||
|
SentMessages sentMessages = new SentMessages(accountName, Arrays.asList(
|
||||||
|
SentMessages.SentMessage.responded("_r1", SentMessages.SentMessage.TargetType.ROOM, message, request, response)
|
||||||
|
));
|
||||||
|
when(account.send(message)).thenReturn(sentMessages);
|
||||||
|
when(service.getAccount(accountName)).thenReturn(account);
|
||||||
|
|
||||||
|
Action.Result result = executable.execute("_id", ctx, payload);
|
||||||
|
|
||||||
|
assertThat(result, notNullValue());
|
||||||
|
assertThat(result, instanceOf(HipChatAction.Result.Executed.class));
|
||||||
|
assertThat(result.status(), equalTo(Action.Result.Status.SUCCESS));
|
||||||
|
assertThat(((HipChatAction.Result.Executed) result).sentMessages(), sameInstance(sentMessages));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParser() throws Exception {
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
builder.field("account", accountName);
|
||||||
|
builder.startObject("message");
|
||||||
|
|
||||||
|
Template body = Template.inline("_body").build();
|
||||||
|
builder.field("body", body);
|
||||||
|
|
||||||
|
Template[] rooms = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template r1 = Template.inline("_r1").build();
|
||||||
|
Template r2 = Template.inline("_r2").build();
|
||||||
|
rooms = new Template[] { r1, r2 };
|
||||||
|
builder.array("room", r1, r2);
|
||||||
|
}
|
||||||
|
Template[] users = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template u1 = Template.inline("_u1").build();
|
||||||
|
Template u2 = Template.inline("_u2").build();
|
||||||
|
users = new Template[] { u1, u2 };
|
||||||
|
builder.array("user", u1, u2);
|
||||||
|
}
|
||||||
|
String from = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
from = randomAsciiOfLength(10);
|
||||||
|
builder.field("from", from);
|
||||||
|
}
|
||||||
|
HipChatMessage.Format format = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
builder.field("format", format.value());
|
||||||
|
}
|
||||||
|
Template color = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
color = Template.inline(randomFrom(HipChatMessage.Color.values()).value()).build();
|
||||||
|
builder.field("color", color);
|
||||||
|
}
|
||||||
|
Boolean notify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
notify = randomBoolean();
|
||||||
|
builder.field("notify", notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.endObject();
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
BytesReference bytes = builder.bytes();
|
||||||
|
logger.info("hipchat action json [{}]", bytes.toUtf8());
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatAction action = HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
|
||||||
|
assertThat(action, notNullValue());
|
||||||
|
assertThat(action.account, is(accountName));
|
||||||
|
assertThat(action.message, notNullValue());
|
||||||
|
assertThat(action.message, is(new HipChatMessage.Template(body, rooms, users, from, format, color, notify)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParser_SelfGenerated() throws Exception {
|
||||||
|
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
Template body = Template.inline("_body").build();
|
||||||
|
HipChatMessage.Template.Builder templateBuilder = new HipChatMessage.Template.Builder(body);
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
builder.field("account", accountName);
|
||||||
|
builder.startObject("message");
|
||||||
|
builder.field("body", body);
|
||||||
|
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template r1 = Template.inline("_r1").build();
|
||||||
|
Template r2 = Template.inline("_r2").build();
|
||||||
|
templateBuilder.addRooms(r1, r2);
|
||||||
|
builder.array("room", r1, r2);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template u1 = Template.inline("_u1").build();
|
||||||
|
Template u2 = Template.inline("_u2").build();
|
||||||
|
templateBuilder.addUsers(u1, u2);
|
||||||
|
builder.array("user", u1, u2);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
String from = randomAsciiOfLength(10);
|
||||||
|
templateBuilder.setFrom(from);
|
||||||
|
builder.field("from", from);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
HipChatMessage.Format format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
templateBuilder.setFormat(format);
|
||||||
|
builder.field("format", format.value());
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
Template color = Template.inline(randomFrom(HipChatMessage.Color.values()).value()).build();
|
||||||
|
templateBuilder.setColor(color);
|
||||||
|
builder.field("color", color);
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
boolean notify = randomBoolean();
|
||||||
|
templateBuilder.setNotify(notify);
|
||||||
|
builder.field("notify", notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.endObject();
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
HipChatMessage.Template template = templateBuilder.build();
|
||||||
|
|
||||||
|
HipChatAction action = new HipChatAction(accountName, template);
|
||||||
|
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder();
|
||||||
|
action.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
BytesReference bytes = builder.bytes();
|
||||||
|
logger.info(bytes.toUtf8());
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatAction parsedAction = HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
|
||||||
|
assertThat(parsedAction, notNullValue());
|
||||||
|
assertThat(parsedAction, is(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ElasticsearchParseException.class)
|
||||||
|
public void testParser_Invalid() throws Exception {
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject().field("unknown_field", "value");
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
HipChatAction.parse("_watch", "_action", parser);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatAccountsTests extends ESTestCase {
|
||||||
|
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
httpClient = mock(HttpClient.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleAccount() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder()
|
||||||
|
.put("default_account", "account1");
|
||||||
|
addAccountSettings("account1", builder);
|
||||||
|
|
||||||
|
HipChatAccounts accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
HipChatAccount account = accounts.account("account1");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
account = accounts.account(null); // falling back on the default
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleAccount_NoExplicitDefault() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder();
|
||||||
|
addAccountSettings("account1", builder);
|
||||||
|
|
||||||
|
HipChatAccounts accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
HipChatAccount account = accounts.account("account1");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
account = accounts.account(null); // falling back on the default
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAccounts() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder()
|
||||||
|
.put("default_account", "account1");
|
||||||
|
addAccountSettings("account1", builder);
|
||||||
|
addAccountSettings("account2", builder);
|
||||||
|
|
||||||
|
HipChatAccounts accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
HipChatAccount account = accounts.account("account1");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
account = accounts.account("account2");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account2"));
|
||||||
|
account = accounts.account(null); // falling back on the default
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAccounts_NoExplicitDefault() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder()
|
||||||
|
.put("default_account", "account1");
|
||||||
|
addAccountSettings("account1", builder);
|
||||||
|
addAccountSettings("account2", builder);
|
||||||
|
|
||||||
|
HipChatAccounts accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
HipChatAccount account = accounts.account("account1");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account1"));
|
||||||
|
account = accounts.account("account2");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, equalTo("account2"));
|
||||||
|
account = accounts.account(null);
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, isOneOf("account1", "account2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testMultipleAccounts_UnknownDefault() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder()
|
||||||
|
.put("default_account", "unknown");
|
||||||
|
addAccountSettings("account1", builder);
|
||||||
|
addAccountSettings("account2", builder);
|
||||||
|
new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testNoAccount() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder();
|
||||||
|
HipChatAccounts accounts = new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
accounts.account(null);
|
||||||
|
fail("no accounts are configured so trying to get the default account should throw an IllegalStateException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testNoAccount_WithDefaultAccount() throws Exception {
|
||||||
|
Settings.Builder builder = Settings.builder()
|
||||||
|
.put("default_account", "unknown");
|
||||||
|
new HipChatAccounts(builder.build(), httpClient, logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAccountSettings(String name, Settings.Builder builder) {
|
||||||
|
HipChatAccount.Profile profile = randomFrom(HipChatAccount.Profile.values());
|
||||||
|
builder.put("account." + name + ".profile", profile.value());
|
||||||
|
builder.put("account." + name + ".auth_token", randomAsciiOfLength(50));
|
||||||
|
if (profile == HipChatAccount.Profile.INTEGRATION) {
|
||||||
|
builder.put("account." + name + ".room", randomAsciiOfLength(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,291 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.support.xcontent.WatcherXContentUtils;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.CoreMatchers.nullValue;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HipChatMessageTests extends ESTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToXContent() throws Exception {
|
||||||
|
String message = randomAsciiOfLength(10);
|
||||||
|
String[] rooms = generateRandomStringArray(3, 10, true);
|
||||||
|
String[] users = generateRandomStringArray(3, 10, true);
|
||||||
|
String from = randomBoolean() ? null : randomAsciiOfLength(10);
|
||||||
|
HipChatMessage.Format format = rarely() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
HipChatMessage.Color color = rarely() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
Boolean notify = rarely() ? null : randomBoolean();
|
||||||
|
HipChatMessage msg = new HipChatMessage(message, rooms, users, from, format, color, notify);
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder();
|
||||||
|
boolean includeTarget = randomBoolean();
|
||||||
|
if (includeTarget && randomBoolean()) {
|
||||||
|
msg.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||||
|
} else {
|
||||||
|
msg.toXContent(builder, ToXContent.EMPTY_PARAMS, includeTarget);
|
||||||
|
}
|
||||||
|
BytesReference bytes = builder.bytes();
|
||||||
|
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
assertThat(parser.currentToken(), is(XContentParser.Token.START_OBJECT));
|
||||||
|
|
||||||
|
message = null;
|
||||||
|
rooms = null;
|
||||||
|
users = null;
|
||||||
|
from = null;
|
||||||
|
format = null;
|
||||||
|
color = null;
|
||||||
|
notify = null;
|
||||||
|
XContentParser.Token token = null;
|
||||||
|
String currentFieldName = null;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if ("body".equals(currentFieldName)) {
|
||||||
|
message = parser.text();
|
||||||
|
} else if ("room".equals(currentFieldName)) {
|
||||||
|
rooms = WatcherXContentUtils.readStringArray(parser, false);
|
||||||
|
} else if ("user".equals(currentFieldName)) {
|
||||||
|
users = WatcherXContentUtils.readStringArray(parser, false);
|
||||||
|
} else if ("from".equals(currentFieldName)) {
|
||||||
|
from = parser.text();
|
||||||
|
} else if ("format".equals(currentFieldName)) {
|
||||||
|
format = HipChatMessage.Format.parse(parser);
|
||||||
|
} else if ("color".equals(currentFieldName)) {
|
||||||
|
color = HipChatMessage.Color.parse(parser);
|
||||||
|
} else if ("notify".equals(currentFieldName)) {
|
||||||
|
notify = parser.booleanValue();
|
||||||
|
} else {
|
||||||
|
fail("unexpected xconent field [" + currentFieldName + "] in hipchat message");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(message, notNullValue());
|
||||||
|
assertThat(message, is(msg.body));
|
||||||
|
if (includeTarget) {
|
||||||
|
if (msg.rooms == null || msg.rooms.length == 0) {
|
||||||
|
assertThat(rooms, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(rooms, arrayContaining(msg.rooms));
|
||||||
|
}
|
||||||
|
if (msg.users == null || msg.users.length == 0) {
|
||||||
|
assertThat(users, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(users, arrayContaining(msg.users));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat(from, is(msg.from));
|
||||||
|
assertThat(format, is(msg.format));
|
||||||
|
assertThat(color, is(msg.color));
|
||||||
|
assertThat(notify, is(msg.notify));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEquals() throws Exception {
|
||||||
|
String message = randomAsciiOfLength(10);
|
||||||
|
String[] rooms = generateRandomStringArray(3, 10, true);
|
||||||
|
String[] users = generateRandomStringArray(3, 10, true);
|
||||||
|
String from = randomBoolean() ? null : randomAsciiOfLength(10);
|
||||||
|
HipChatMessage.Format format = rarely() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
HipChatMessage.Color color = rarely() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
Boolean notify = rarely() ? null : randomBoolean();
|
||||||
|
HipChatMessage msg1 = new HipChatMessage(message, rooms, users, from, format, color, notify);
|
||||||
|
|
||||||
|
boolean equals = randomBoolean();
|
||||||
|
if (!equals) {
|
||||||
|
equals = true;
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
message = "another message";
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
rooms = rooms == null ? new String[] { "roomX" } : randomBoolean() ? null : new String[] { "roomX" , "roomY"};
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
users = users == null ? new String[] { "userX" } : randomBoolean() ? null : new String[] { "userX", "userY" };
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
from = from == null ? "fromX" : randomBoolean() ? null : "fromY";
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
format = format == null ?
|
||||||
|
randomFrom(HipChatMessage.Format.values()) :
|
||||||
|
randomBoolean() ?
|
||||||
|
null :
|
||||||
|
randomFrom(HipChatMessage.Format.values(), format);
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
color = color == null ?
|
||||||
|
randomFrom(HipChatMessage.Color.values()) :
|
||||||
|
randomBoolean() ?
|
||||||
|
null :
|
||||||
|
randomFrom(HipChatMessage.Color.values(), color);
|
||||||
|
}
|
||||||
|
if (rarely()) {
|
||||||
|
equals = false;
|
||||||
|
notify = notify == null ? (Boolean) randomBoolean() : randomBoolean() ? null : (Boolean) randomBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HipChatMessage msg2 = new HipChatMessage(message, rooms, users, from, format, color, notify);
|
||||||
|
assertThat(msg1.equals(msg2), is(equals));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTemplate_Parse() throws Exception {
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder();
|
||||||
|
jsonBuilder.startObject();
|
||||||
|
|
||||||
|
Template body = Template.inline(randomAsciiOfLength(200)).build();
|
||||||
|
jsonBuilder.field("body", body, ToXContent.EMPTY_PARAMS);
|
||||||
|
Template[] rooms = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
jsonBuilder.startArray("room");
|
||||||
|
rooms = new Template[randomIntBetween(1, 3)];
|
||||||
|
for (int i = 0; i < rooms.length; i++) {
|
||||||
|
rooms[i] = Template.inline(randomAsciiOfLength(10)).build();
|
||||||
|
rooms[i].toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
}
|
||||||
|
jsonBuilder.endArray();
|
||||||
|
}
|
||||||
|
Template[] users = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
jsonBuilder.startArray("user");
|
||||||
|
users = new Template[randomIntBetween(1, 3)];
|
||||||
|
for (int i = 0; i < users.length; i++) {
|
||||||
|
users[i] = Template.inline(randomAsciiOfLength(10)).build();
|
||||||
|
users[i].toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
}
|
||||||
|
jsonBuilder.endArray();
|
||||||
|
}
|
||||||
|
String from = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
from = randomAsciiOfLength(10);
|
||||||
|
jsonBuilder.field("from", from);
|
||||||
|
}
|
||||||
|
Template color = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
color = Template.inline(randomAsciiOfLength(10)).build();
|
||||||
|
jsonBuilder.field("color", color, ToXContent.EMPTY_PARAMS);
|
||||||
|
}
|
||||||
|
HipChatMessage.Format format = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
jsonBuilder.field("format", format, ToXContent.EMPTY_PARAMS);
|
||||||
|
}
|
||||||
|
Boolean notify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
notify = randomBoolean();
|
||||||
|
jsonBuilder.field("notify", notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
BytesReference bytes = jsonBuilder.bytes();
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatMessage.Template template = HipChatMessage.Template.parse(parser);
|
||||||
|
|
||||||
|
assertThat(template, notNullValue());
|
||||||
|
assertThat(template.body, is(body));
|
||||||
|
if (rooms == null) {
|
||||||
|
assertThat(template.rooms, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(template.rooms, arrayContaining(rooms));
|
||||||
|
}
|
||||||
|
if (users == null) {
|
||||||
|
assertThat(template.users, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(template.users, arrayContaining(users));
|
||||||
|
}
|
||||||
|
assertThat(template.from, is(from));
|
||||||
|
assertThat(template.color, is(color));
|
||||||
|
assertThat(template.format, is(format));
|
||||||
|
assertThat(template.notify, is(notify));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTemplate_ParseSelfGenerated() throws Exception {
|
||||||
|
Template body = Template.inline(randomAsciiOfLength(10)).build();
|
||||||
|
HipChatMessage.Template.Builder templateBuilder = new HipChatMessage.Template.Builder(body);
|
||||||
|
|
||||||
|
if (randomBoolean()) {
|
||||||
|
int count = randomIntBetween(1, 3);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
templateBuilder.addRooms(Template.inline(randomAsciiOfLength(10)).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
int count = randomIntBetween(1, 3);
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
templateBuilder.addUsers(Template.inline(randomAsciiOfLength(10)).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
templateBuilder.setFrom(randomAsciiOfLength(10));
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
templateBuilder.setColor(Template.inline(randomAsciiOfLength(5)).build());
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
templateBuilder.setFormat(randomFrom(HipChatMessage.Format.values()));
|
||||||
|
}
|
||||||
|
if (randomBoolean()) {
|
||||||
|
templateBuilder.setNotify(randomBoolean());
|
||||||
|
}
|
||||||
|
HipChatMessage.Template template = templateBuilder.build();
|
||||||
|
|
||||||
|
XContentBuilder jsonBuilder = jsonBuilder();
|
||||||
|
template.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
BytesReference bytes = jsonBuilder.bytes();
|
||||||
|
|
||||||
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
|
parser.nextToken();
|
||||||
|
|
||||||
|
HipChatMessage.Template parsed = HipChatMessage.Template.parse(parser);
|
||||||
|
|
||||||
|
assertThat(parsed, equalTo(template));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static <E extends Enum> E randomFrom(E[] values, E... exclude) {
|
||||||
|
List<E> excludes = Arrays.asList(exclude);
|
||||||
|
List<E> includes = new ArrayList<>();
|
||||||
|
for (E value : values) {
|
||||||
|
if (!excludes.contains(value)) {
|
||||||
|
includes.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return randomFrom(includes);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.test.junit.annotations.Network;
|
||||||
|
import org.elasticsearch.watcher.actions.hipchat.HipChatAction;
|
||||||
|
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
|
||||||
|
import org.elasticsearch.watcher.transport.actions.put.PutWatchResponse;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||||
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
|
import static org.elasticsearch.watcher.actions.ActionBuilders.hipchatAction;
|
||||||
|
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
|
||||||
|
import static org.elasticsearch.watcher.condition.ConditionBuilders.alwaysCondition;
|
||||||
|
import static org.elasticsearch.watcher.input.InputBuilders.simpleInput;
|
||||||
|
import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule;
|
||||||
|
import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Network
|
||||||
|
public class HipChatServiceIT extends AbstractWatcherIntegrationTests {
|
||||||
|
|
||||||
|
private HipChatService service;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean timeWarped() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean enableShield() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
return Settings.builder()
|
||||||
|
.put(super.nodeSettings(nodeOrdinal))
|
||||||
|
|
||||||
|
// this is for the `test-watcher-integration` group level integration in HipChat
|
||||||
|
.put("watcher.actions.hipchat.service.account.integration_account.profile", "integration")
|
||||||
|
.put("watcher.actions.hipchat.service.account.integration_account.auth_token", "huuS9v7ccuOy3ZBWWWr1vt8Lqu3sQnLUE81nrLZU")
|
||||||
|
.put("watcher.actions.hipchat.service.account.integration_account.room", "test-watcher")
|
||||||
|
|
||||||
|
// this is for the Watcher Test account in HipChat
|
||||||
|
.put("watcher.actions.hipchat.service.account.user_account.profile", "user")
|
||||||
|
.put("watcher.actions.hipchat.service.account.user_account.auth_token", "FYVx16oDH78ZW9r13wtXbcszyoyA7oX5tiMWg9X0")
|
||||||
|
|
||||||
|
// this is for the `test-watcher-v1` notification token
|
||||||
|
.put("watcher.actions.hipchat.service.account.v1_account.profile", "v1")
|
||||||
|
.put("watcher.actions.hipchat.service.account.v1_account.auth_token", "a734baf62df618b96dda55b323fc30")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
service = getInstanceFromMaster(HipChatService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendMessage_V1Account() throws Exception {
|
||||||
|
HipChatMessage hipChatMessage = new HipChatMessage(
|
||||||
|
"/code HipChatServiceIT#testSendMessage_V1Account",
|
||||||
|
new String[] { "test-watcher", "test-watcher-2" },
|
||||||
|
null, // users are unsupported in v1
|
||||||
|
"watcher-tests",
|
||||||
|
HipChatMessage.Format.TEXT,
|
||||||
|
randomFrom(HipChatMessage.Color.values()),
|
||||||
|
true);
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount("v1_account");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
SentMessages messages = account.send(hipChatMessage);
|
||||||
|
assertThat(messages.count(), is(2));
|
||||||
|
for (SentMessages.SentMessage message : messages) {
|
||||||
|
assertThat(message.successful(), is(true));
|
||||||
|
assertThat(message.request, notNullValue());
|
||||||
|
assertThat(message.response, notNullValue());
|
||||||
|
assertThat(message.response.status(), lessThan(300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendMessage_IntegrationAccount() throws Exception {
|
||||||
|
HipChatMessage hipChatMessage = new HipChatMessage(
|
||||||
|
"/code HipChatServiceIT#testSendMessage_IntegrationAccount",
|
||||||
|
null, // custom rooms are unsupported by integration profiles
|
||||||
|
null, // users are unsupported by integration profiles
|
||||||
|
null, // custom "from" is not supported by integration profiles
|
||||||
|
HipChatMessage.Format.TEXT,
|
||||||
|
randomFrom(HipChatMessage.Color.values()),
|
||||||
|
true);
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount("integration_account");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
SentMessages messages = account.send(hipChatMessage);
|
||||||
|
assertThat(messages.count(), is(1));
|
||||||
|
for (SentMessages.SentMessage message : messages) {
|
||||||
|
assertThat(message.successful(), is(true));
|
||||||
|
assertThat(message.request, notNullValue());
|
||||||
|
assertThat(message.response, notNullValue());
|
||||||
|
assertThat(message.response.status(), lessThan(300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSendMessage_UserAccount() throws Exception {
|
||||||
|
HipChatMessage hipChatMessage = new HipChatMessage(
|
||||||
|
"/code HipChatServiceIT#testSendMessage_UserAccount",
|
||||||
|
new String[] { "test-watcher", "test-watcher-2" },
|
||||||
|
new String[] { "watcher@elastic.co" },
|
||||||
|
null, // custom "from" is not supported by integration profiles
|
||||||
|
HipChatMessage.Format.TEXT,
|
||||||
|
randomFrom(HipChatMessage.Color.values()),
|
||||||
|
false);
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount("user_account");
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
SentMessages messages = account.send(hipChatMessage);
|
||||||
|
assertThat(messages.count(), is(3));
|
||||||
|
for (SentMessages.SentMessage message : messages) {
|
||||||
|
assertThat(message.successful(), is(true));
|
||||||
|
assertThat(message.request, notNullValue());
|
||||||
|
assertThat(message.response, notNullValue());
|
||||||
|
assertThat(message.response.status(), lessThan(300));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWatchWithHipChatAction() throws Exception {
|
||||||
|
|
||||||
|
|
||||||
|
HipChatAccount.Profile profile = randomFrom(HipChatAccount.Profile.values());
|
||||||
|
String account;
|
||||||
|
HipChatAction.Builder actionBuilder;
|
||||||
|
switch (profile) {
|
||||||
|
case USER:
|
||||||
|
account = "user_account";
|
||||||
|
actionBuilder = hipchatAction(account, "/code {{ctx.payload.ref}}")
|
||||||
|
.addRooms("test-watcher", "test-watcher-2")
|
||||||
|
.addUsers("watcher@elastic.co")
|
||||||
|
.setFormat(HipChatMessage.Format.TEXT)
|
||||||
|
.setColor(randomFrom(HipChatMessage.Color.values()))
|
||||||
|
.setNotify(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case INTEGRATION:
|
||||||
|
account = "integration_account";
|
||||||
|
actionBuilder = hipchatAction(account, "/code {{ctx.payload.ref}}")
|
||||||
|
.setFormat(HipChatMessage.Format.TEXT)
|
||||||
|
.setColor(randomFrom(HipChatMessage.Color.values()))
|
||||||
|
.setNotify(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertThat(profile, is(HipChatAccount.Profile.V1));
|
||||||
|
account = "v1_account";
|
||||||
|
actionBuilder = hipchatAction(account, "/code {{ctx.payload.ref}}")
|
||||||
|
.addRooms("test-watcher", "test-watcher-2")
|
||||||
|
.setFrom("watcher-test")
|
||||||
|
.setFormat(HipChatMessage.Format.TEXT)
|
||||||
|
.setColor(randomFrom(HipChatMessage.Color.values()))
|
||||||
|
.setNotify(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("1").setSource(watchBuilder()
|
||||||
|
.trigger(schedule(interval("10m")))
|
||||||
|
.input(simpleInput("ref", "HipChatServiceIT#testWatchWithHipChatAction"))
|
||||||
|
.condition(alwaysCondition())
|
||||||
|
.addAction("hipchat", actionBuilder))
|
||||||
|
.execute().get();
|
||||||
|
|
||||||
|
assertThat(putWatchResponse.isCreated(), is(true));
|
||||||
|
|
||||||
|
timeWarp().scheduler().trigger("1");
|
||||||
|
flush();
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
assertWatchWithMinimumPerformedActionsCount("1", 1L, false);
|
||||||
|
|
||||||
|
SearchResponse response = searchHistory(searchSource().query(boolQuery()
|
||||||
|
.must(termQuery("result.actions.id", "hipchat"))
|
||||||
|
.must(termQuery("result.actions.type", "hipchat"))
|
||||||
|
.must(termQuery("result.actions.status", "success"))
|
||||||
|
.must(termQuery("result.actions.hipchat.account", account))
|
||||||
|
.must(termQuery("result.actions.hipchat.sent_messages.status", "success"))));
|
||||||
|
|
||||||
|
assertThat(response, notNullValue());
|
||||||
|
assertThat(response.getHits().getTotalHits(), is(1L));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class IntegrationAccountTests extends ESTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSettings() throws Exception {
|
||||||
|
String accountName = "_name";
|
||||||
|
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
|
||||||
|
String authToken = randomAsciiOfLength(50);
|
||||||
|
sb.put(IntegrationAccount.AUTH_TOKEN_SETTING, authToken);
|
||||||
|
|
||||||
|
String host = HipChatServer.DEFAULT.host();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
host = randomAsciiOfLength(10);
|
||||||
|
sb.put(HipChatServer.HOST_SETTING, host);
|
||||||
|
}
|
||||||
|
int port = HipChatServer.DEFAULT.port();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
port = randomIntBetween(300, 400);
|
||||||
|
sb.put(HipChatServer.PORT_SETTING, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
String room = randomAsciiOfLength(10);
|
||||||
|
sb.put(IntegrationAccount.ROOM_SETTING, room);
|
||||||
|
|
||||||
|
HipChatMessage.Format defaultFormat = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultFormat = randomFrom(HipChatMessage.Format.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_FORMAT_SETTING, defaultFormat);
|
||||||
|
}
|
||||||
|
HipChatMessage.Color defaultColor = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultColor = randomFrom(HipChatMessage.Color.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_COLOR_SETTING, defaultColor);
|
||||||
|
}
|
||||||
|
Boolean defaultNotify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultNotify = randomBoolean();
|
||||||
|
sb.put(HipChatAccount.DEFAULT_NOTIFY_SETTING, defaultNotify);
|
||||||
|
}
|
||||||
|
Settings settings = sb.build();
|
||||||
|
|
||||||
|
IntegrationAccount account = new IntegrationAccount(accountName, settings, HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.INTEGRATION));
|
||||||
|
assertThat(account.name, equalTo(accountName));
|
||||||
|
assertThat(account.server.host(), is(host));
|
||||||
|
assertThat(account.server.port(), is(port));
|
||||||
|
assertThat(account.authToken, is(authToken));
|
||||||
|
assertThat(account.room, is(room));
|
||||||
|
assertThat(account.defaults.format, is(defaultFormat));
|
||||||
|
assertThat(account.defaults.color, is(defaultColor));
|
||||||
|
assertThat(account.defaults.notify, is(defaultNotify));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSettings_NoAuthToken() throws Exception {
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
sb.put(IntegrationAccount.ROOM_SETTING, randomAsciiOfLength(10));
|
||||||
|
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSettings_WithoutRoom() throws Exception {
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
sb.put(IntegrationAccount.AUTH_TOKEN_SETTING, randomAsciiOfLength(50));
|
||||||
|
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSettings_WithoutMultipleRooms() throws Exception {
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
sb.put(IntegrationAccount.AUTH_TOKEN_SETTING, randomAsciiOfLength(50));
|
||||||
|
sb.put(IntegrationAccount.ROOM_SETTING, "_r1,_r2");
|
||||||
|
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSend() throws Exception {
|
||||||
|
HttpClient httpClient = mock(HttpClient.class);
|
||||||
|
IntegrationAccount account = new IntegrationAccount("_name", Settings.builder()
|
||||||
|
.put("host", "_host")
|
||||||
|
.put("port", "443")
|
||||||
|
.put("auth_token", "_token")
|
||||||
|
.put("room", "_room")
|
||||||
|
.build(), HipChatServer.DEFAULT, httpClient, mock(ESLogger.class));
|
||||||
|
|
||||||
|
HipChatMessage.Format format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
HipChatMessage.Color color = randomFrom(HipChatMessage.Color.values());
|
||||||
|
Boolean notify = randomBoolean();
|
||||||
|
final HipChatMessage message = new HipChatMessage("_body", null, null, null, format, color, notify);
|
||||||
|
|
||||||
|
HttpRequest req = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/room/_room/notification")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer _token")
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
builder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
builder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
builder.field("color", String.valueOf(message.color.value()));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse res = mock(HttpResponse.class);
|
||||||
|
when(res.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(req)).thenReturn(res);
|
||||||
|
|
||||||
|
account.send(message);
|
||||||
|
|
||||||
|
verify(httpClient).execute(req);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,281 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.node.settings.NodeSettingsService;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.shield.WatcherSettingsFilter;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InternalHipChatServiceTests extends ESTestCase {
|
||||||
|
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private NodeSettingsService nodeSettingsService;
|
||||||
|
private WatcherSettingsFilter settingsFilter;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
httpClient = mock(HttpClient.class);
|
||||||
|
nodeSettingsService = mock(NodeSettingsService.class);
|
||||||
|
settingsFilter = mock(WatcherSettingsFilter.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleAccount_V1() throws Exception {
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
String host = randomBoolean() ? null : "_host";
|
||||||
|
int port = randomBoolean() ? -1 : randomIntBetween(300, 400);
|
||||||
|
String defaultRoom = randomBoolean() ? null : "_r1, _r2";
|
||||||
|
String defaultFrom = randomBoolean() ? null : "_from";
|
||||||
|
HipChatMessage.Color defaultColor = randomBoolean() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
HipChatMessage.Format defaultFormat = randomBoolean() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
Boolean defaultNotify = randomBoolean() ? null : (Boolean) randomBoolean();
|
||||||
|
Settings.Builder settingsBuilder = Settings.builder()
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".profile", HipChatAccount.Profile.V1.value())
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".auth_token", "_token");
|
||||||
|
if (host != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".host", host);
|
||||||
|
}
|
||||||
|
if (port > 0) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".port", port);
|
||||||
|
}
|
||||||
|
buildMessageDefaults(accountName, settingsBuilder, defaultRoom, null, defaultFrom, defaultColor, defaultFormat, defaultNotify);
|
||||||
|
InternalHipChatService service = new InternalHipChatService(settingsBuilder.build(), httpClient, nodeSettingsService, settingsFilter);
|
||||||
|
service.start();
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount(accountName);
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, is(accountName));
|
||||||
|
assertThat(account.authToken, is("_token"));
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.V1));
|
||||||
|
assertThat(account.httpClient, is(httpClient));
|
||||||
|
assertThat(account.server, notNullValue());
|
||||||
|
assertThat(account.server.host(), is(host != null ? host : HipChatServer.DEFAULT.host()));
|
||||||
|
assertThat(account.server.port(), is(port > 0 ? port : HipChatServer.DEFAULT.port()));
|
||||||
|
assertThat(account, instanceOf(V1Account.class));
|
||||||
|
if (defaultRoom == null) {
|
||||||
|
assertThat(((V1Account) account).defaults.rooms, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(((V1Account) account).defaults.rooms, arrayContaining("_r1", "_r2"));
|
||||||
|
}
|
||||||
|
assertThat(((V1Account) account).defaults.from, is(defaultFrom));
|
||||||
|
assertThat(((V1Account) account).defaults.color, is(defaultColor));
|
||||||
|
assertThat(((V1Account) account).defaults.format, is(defaultFormat));
|
||||||
|
assertThat(((V1Account) account).defaults.notify, is(defaultNotify));
|
||||||
|
|
||||||
|
// with a single account defined, making sure that that account is set to the default one.
|
||||||
|
assertThat(service.getDefaultAccount(), sameInstance(account));
|
||||||
|
|
||||||
|
assertThatSettingsFilterWasAdded();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleAccount_Integration() throws Exception {
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
String host = randomBoolean() ? null : "_host";
|
||||||
|
int port = randomBoolean() ? -1 : randomIntBetween(300, 400);
|
||||||
|
String room = randomAsciiOfLength(10);
|
||||||
|
String defaultFrom = randomBoolean() ? null : "_from";
|
||||||
|
HipChatMessage.Color defaultColor = randomBoolean() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
HipChatMessage.Format defaultFormat = randomBoolean() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
Boolean defaultNotify = randomBoolean() ? null : (Boolean) randomBoolean();
|
||||||
|
Settings.Builder settingsBuilder = Settings.builder()
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".profile", HipChatAccount.Profile.INTEGRATION.value())
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".auth_token", "_token")
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".room", room);
|
||||||
|
if (host != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".host", host);
|
||||||
|
}
|
||||||
|
if (port > 0) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".port", port);
|
||||||
|
}
|
||||||
|
buildMessageDefaults(accountName, settingsBuilder, null, null, defaultFrom, defaultColor, defaultFormat, defaultNotify);
|
||||||
|
InternalHipChatService service = new InternalHipChatService(settingsBuilder.build(), httpClient, nodeSettingsService, settingsFilter);
|
||||||
|
service.start();
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount(accountName);
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, is(accountName));
|
||||||
|
assertThat(account.authToken, is("_token"));
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.INTEGRATION));
|
||||||
|
assertThat(account.httpClient, is(httpClient));
|
||||||
|
assertThat(account.server, notNullValue());
|
||||||
|
assertThat(account.server.host(), is(host != null ? host : HipChatServer.DEFAULT.host()));
|
||||||
|
assertThat(account.server.port(), is(port > 0 ? port : HipChatServer.DEFAULT.port()));
|
||||||
|
assertThat(account, instanceOf(IntegrationAccount.class));
|
||||||
|
assertThat(((IntegrationAccount) account).room, is(room));
|
||||||
|
assertThat(((IntegrationAccount) account).defaults.color, is(defaultColor));
|
||||||
|
assertThat(((IntegrationAccount) account).defaults.format, is(defaultFormat));
|
||||||
|
assertThat(((IntegrationAccount) account).defaults.notify, is(defaultNotify));
|
||||||
|
|
||||||
|
// with a single account defined, making sure that that account is set to the default one.
|
||||||
|
assertThat(service.getDefaultAccount(), sameInstance(account));
|
||||||
|
|
||||||
|
assertThatSettingsFilterWasAdded();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSingleAccount_Integration_NoRoomSetting() throws Exception {
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
Settings.Builder settingsBuilder = Settings.builder()
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".profile", HipChatAccount.Profile.INTEGRATION.value())
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".auth_token", "_token");
|
||||||
|
InternalHipChatService service = new InternalHipChatService(settingsBuilder.build(), httpClient, nodeSettingsService, settingsFilter);
|
||||||
|
service.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleAccount_User() throws Exception {
|
||||||
|
String accountName = randomAsciiOfLength(10);
|
||||||
|
String host = randomBoolean() ? null : "_host";
|
||||||
|
int port = randomBoolean() ? -1 : randomIntBetween(300, 400);
|
||||||
|
String defaultRoom = randomBoolean() ? null : "_r1, _r2";
|
||||||
|
String defaultUser = randomBoolean() ? null : "_u1, _u2";
|
||||||
|
HipChatMessage.Color defaultColor = randomBoolean() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
HipChatMessage.Format defaultFormat = randomBoolean() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
Boolean defaultNotify = randomBoolean() ? null : (Boolean) randomBoolean();
|
||||||
|
Settings.Builder settingsBuilder = Settings.builder()
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".profile", HipChatAccount.Profile.USER.value())
|
||||||
|
.put("watcher.actions.hipchat.service.account." + accountName + ".auth_token", "_token");
|
||||||
|
if (host != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".host", host);
|
||||||
|
}
|
||||||
|
if (port > 0) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + accountName + ".port", port);
|
||||||
|
}
|
||||||
|
buildMessageDefaults(accountName, settingsBuilder, defaultRoom, defaultUser, null, defaultColor, defaultFormat, defaultNotify);
|
||||||
|
InternalHipChatService service = new InternalHipChatService(settingsBuilder.build(), httpClient, nodeSettingsService, settingsFilter);
|
||||||
|
service.start();
|
||||||
|
|
||||||
|
HipChatAccount account = service.getAccount(accountName);
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, is(accountName));
|
||||||
|
assertThat(account.authToken, is("_token"));
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.USER));
|
||||||
|
assertThat(account.httpClient, is(httpClient));
|
||||||
|
assertThat(account.server, notNullValue());
|
||||||
|
assertThat(account.server.host(), is(host != null ? host : HipChatServer.DEFAULT.host()));
|
||||||
|
assertThat(account.server.port(), is(port > 0 ? port : HipChatServer.DEFAULT.port()));
|
||||||
|
assertThat(account, instanceOf(UserAccount.class));
|
||||||
|
if (defaultRoom == null) {
|
||||||
|
assertThat(((UserAccount) account).defaults.rooms, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(((UserAccount) account).defaults.rooms, arrayContaining("_r1", "_r2"));
|
||||||
|
}
|
||||||
|
if (defaultUser == null) {
|
||||||
|
assertThat(((UserAccount) account).defaults.users, nullValue());
|
||||||
|
} else {
|
||||||
|
assertThat(((UserAccount) account).defaults.users, arrayContaining("_u1", "_u2"));
|
||||||
|
}
|
||||||
|
assertThat(((UserAccount) account).defaults.color, is(defaultColor));
|
||||||
|
assertThat(((UserAccount) account).defaults.format, is(defaultFormat));
|
||||||
|
assertThat(((UserAccount) account).defaults.notify, is(defaultNotify));
|
||||||
|
|
||||||
|
// with a single account defined, making sure that that account is set to the default one.
|
||||||
|
assertThat(service.getDefaultAccount(), sameInstance(account));
|
||||||
|
|
||||||
|
assertThatSettingsFilterWasAdded();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAccounts() throws Exception {
|
||||||
|
HipChatMessage.Color defaultColor = randomBoolean() ? null : randomFrom(HipChatMessage.Color.values());
|
||||||
|
HipChatMessage.Format defaultFormat = randomBoolean() ? null : randomFrom(HipChatMessage.Format.values());
|
||||||
|
Boolean defaultNotify = randomBoolean() ? null : (Boolean) randomBoolean();
|
||||||
|
Settings.Builder settingsBuilder = Settings.builder();
|
||||||
|
String defaultAccount = "_a" + randomIntBetween(0, 4);
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.default_account", defaultAccount);
|
||||||
|
|
||||||
|
boolean customGlobalServer = randomBoolean();
|
||||||
|
if (customGlobalServer) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.host", "_host_global");
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.port", 299);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String name = "_a" + i;
|
||||||
|
String prefix = "watcher.actions.hipchat.service.account." + name;
|
||||||
|
HipChatAccount.Profile profile = randomFrom(HipChatAccount.Profile.values());
|
||||||
|
settingsBuilder.put(prefix + ".profile", profile);
|
||||||
|
settingsBuilder.put(prefix + ".auth_token", "_token" + i);
|
||||||
|
if (profile == HipChatAccount.Profile.INTEGRATION) {
|
||||||
|
settingsBuilder.put(prefix + ".room", "_room" + i);
|
||||||
|
}
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
settingsBuilder.put(prefix + ".host", "_host" + i);
|
||||||
|
settingsBuilder.put(prefix + ".port", 300 + i);
|
||||||
|
}
|
||||||
|
buildMessageDefaults(name, settingsBuilder, null, null, null, defaultColor, defaultFormat, defaultNotify);
|
||||||
|
}
|
||||||
|
|
||||||
|
InternalHipChatService service = new InternalHipChatService(settingsBuilder.build(), httpClient, nodeSettingsService, settingsFilter);
|
||||||
|
service.start();
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
String name = "_a" + i;
|
||||||
|
HipChatAccount account = service.getAccount(name);
|
||||||
|
assertThat(account, notNullValue());
|
||||||
|
assertThat(account.name, is(name));
|
||||||
|
assertThat(account.authToken, is("_token" + i));
|
||||||
|
assertThat(account.profile, notNullValue());
|
||||||
|
if (account.profile == HipChatAccount.Profile.INTEGRATION) {
|
||||||
|
assertThat(account, instanceOf(IntegrationAccount.class));
|
||||||
|
assertThat(((IntegrationAccount) account).room, is("_room" + i));
|
||||||
|
}
|
||||||
|
assertThat(account.httpClient, is(httpClient));
|
||||||
|
assertThat(account.server, notNullValue());
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
assertThat(account.server.host(), is("_host" + i));
|
||||||
|
assertThat(account.server.port(), is(300 + i));
|
||||||
|
} else if (customGlobalServer) {
|
||||||
|
assertThat(account.server.host(), is("_host_global"));
|
||||||
|
assertThat(account.server.port(), is(299));
|
||||||
|
} else {
|
||||||
|
assertThat(account.server.host(), is(HipChatServer.DEFAULT.host()));
|
||||||
|
assertThat(account.server.port(), is(HipChatServer.DEFAULT.port()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(service.getDefaultAccount(), sameInstance(service.getAccount(defaultAccount)));
|
||||||
|
|
||||||
|
assertThatSettingsFilterWasAdded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertThatSettingsFilterWasAdded() {
|
||||||
|
verify(settingsFilter, times(1)).filterOut("watcher.actions.hipchat.service.account.*.auth_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildMessageDefaults(String account, Settings.Builder settingsBuilder, String room, String user, String from, HipChatMessage.Color color, HipChatMessage.Format format, Boolean notify) {
|
||||||
|
if (room != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.room", room);
|
||||||
|
}
|
||||||
|
if (user != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.user", user);
|
||||||
|
}
|
||||||
|
if (from != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.from", from);
|
||||||
|
}
|
||||||
|
if (color != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.color", color.value());
|
||||||
|
}
|
||||||
|
if (format != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.format", format);
|
||||||
|
}
|
||||||
|
if (notify != null) {
|
||||||
|
settingsBuilder.put("watcher.actions.hipchat.service.account." + account + ".message_defaults.notify", notify);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class UserAccountTests extends ESTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSettings() throws Exception {
|
||||||
|
String accountName = "_name";
|
||||||
|
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
|
||||||
|
String authToken = randomAsciiOfLength(50);
|
||||||
|
sb.put(UserAccount.AUTH_TOKEN_SETTING, authToken);
|
||||||
|
|
||||||
|
String host = HipChatServer.DEFAULT.host();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
host = randomAsciiOfLength(10);
|
||||||
|
sb.put(HipChatServer.HOST_SETTING, host);
|
||||||
|
}
|
||||||
|
int port = HipChatServer.DEFAULT.port();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
port = randomIntBetween(300, 400);
|
||||||
|
sb.put(HipChatServer.PORT_SETTING, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] defaultRooms = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultRooms = new String[] { "_r1", "_r2" };
|
||||||
|
sb.put(HipChatAccount.DEFAULT_ROOM_SETTING, "_r1,_r2");
|
||||||
|
}
|
||||||
|
String[] defaultUsers = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultUsers = new String[] { "_u1", "_u2" };
|
||||||
|
sb.put(HipChatAccount.DEFAULT_USER_SETTING, "_u1,_u2");
|
||||||
|
}
|
||||||
|
HipChatMessage.Format defaultFormat = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultFormat = randomFrom(HipChatMessage.Format.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_FORMAT_SETTING, defaultFormat);
|
||||||
|
}
|
||||||
|
HipChatMessage.Color defaultColor = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultColor = randomFrom(HipChatMessage.Color.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_COLOR_SETTING, defaultColor);
|
||||||
|
}
|
||||||
|
Boolean defaultNotify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultNotify = randomBoolean();
|
||||||
|
sb.put(HipChatAccount.DEFAULT_NOTIFY_SETTING, defaultNotify);
|
||||||
|
}
|
||||||
|
Settings settings = sb.build();
|
||||||
|
|
||||||
|
UserAccount account = new UserAccount(accountName, settings, HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.USER));
|
||||||
|
assertThat(account.name, equalTo(accountName));
|
||||||
|
assertThat(account.server.host(), is(host));
|
||||||
|
assertThat(account.server.port(), is(port));
|
||||||
|
assertThat(account.authToken, is(authToken));
|
||||||
|
if (defaultRooms != null) {
|
||||||
|
assertThat(account.defaults.rooms, arrayContaining(defaultRooms));
|
||||||
|
} else {
|
||||||
|
assertThat(account.defaults.rooms, nullValue());
|
||||||
|
}
|
||||||
|
if (defaultUsers != null) {
|
||||||
|
assertThat(account.defaults.users, arrayContaining(defaultUsers));
|
||||||
|
} else {
|
||||||
|
assertThat(account.defaults.users, nullValue());
|
||||||
|
}
|
||||||
|
assertThat(account.defaults.format, is(defaultFormat));
|
||||||
|
assertThat(account.defaults.color, is(defaultColor));
|
||||||
|
assertThat(account.defaults.notify, is(defaultNotify));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSettings_NoAuthToken() throws Exception {
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
new UserAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSend() throws Exception {
|
||||||
|
HttpClient httpClient = mock(HttpClient.class);
|
||||||
|
UserAccount account = new UserAccount("_name", Settings.builder()
|
||||||
|
.put("host", "_host")
|
||||||
|
.put("port", "443")
|
||||||
|
.put("auth_token", "_token")
|
||||||
|
.build(), HipChatServer.DEFAULT, httpClient, mock(ESLogger.class));
|
||||||
|
|
||||||
|
HipChatMessage.Format format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
HipChatMessage.Color color = randomFrom(HipChatMessage.Color.values());
|
||||||
|
Boolean notify = randomBoolean();
|
||||||
|
final HipChatMessage message = new HipChatMessage("_body", new String[] { "_r1", "_r2" }, new String[] { "_u1", "_u2" }, null, format, color, notify);
|
||||||
|
|
||||||
|
HttpRequest reqR1 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/room/_r1/notification")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer _token")
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
builder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
builder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
builder.field("color", String.valueOf(message.color.value()));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (r1): " + jsonBuilder().value(reqR1).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse resR1 = mock(HttpResponse.class);
|
||||||
|
when(resR1.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(reqR1)).thenReturn(resR1);
|
||||||
|
|
||||||
|
HttpRequest reqR2 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/room/_r2/notification")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer _token")
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
builder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
builder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
if (message.color != null) {
|
||||||
|
builder.field("color", String.valueOf(message.color.value()));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (r2): " + jsonBuilder().value(reqR1).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse resR2 = mock(HttpResponse.class);
|
||||||
|
when(resR2.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(reqR2)).thenReturn(resR2);
|
||||||
|
|
||||||
|
HttpRequest reqU1 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/user/_u1/message")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer _token")
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
builder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
builder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (u1): " + jsonBuilder().value(reqU1).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse resU1 = mock(HttpResponse.class);
|
||||||
|
when(resU1.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(reqU1)).thenReturn(resU1);
|
||||||
|
|
||||||
|
HttpRequest reqU2 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v2/user/_u2/message")
|
||||||
|
.setHeader("Content-Type", "application/json")
|
||||||
|
.setHeader("Authorization", "Bearer _token")
|
||||||
|
.body(XContentHelper.toString(new ToXContent() {
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field("message", message.body);
|
||||||
|
if (message.format != null) {
|
||||||
|
builder.field("message_format", message.format.value());
|
||||||
|
}
|
||||||
|
if (message.notify != null) {
|
||||||
|
builder.field("notify", message.notify);
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (u2): " + jsonBuilder().value(reqU2).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse resU2 = mock(HttpResponse.class);
|
||||||
|
when(resU2.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(reqU2)).thenReturn(resU2);
|
||||||
|
|
||||||
|
account.send(message);
|
||||||
|
|
||||||
|
verify(httpClient).execute(reqR1);
|
||||||
|
verify(httpClient).execute(reqR2);
|
||||||
|
verify(httpClient).execute(reqU2);
|
||||||
|
verify(httpClient).execute(reqU2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.watcher.actions.hipchat.service;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class V1AccountTests extends ESTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSettings() throws Exception {
|
||||||
|
String accountName = "_name";
|
||||||
|
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
|
||||||
|
String authToken = randomAsciiOfLength(50);
|
||||||
|
sb.put(V1Account.AUTH_TOKEN_SETTING, authToken);
|
||||||
|
|
||||||
|
String host = HipChatServer.DEFAULT.host();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
host = randomAsciiOfLength(10);
|
||||||
|
sb.put(HipChatServer.HOST_SETTING, host);
|
||||||
|
}
|
||||||
|
int port = HipChatServer.DEFAULT.port();
|
||||||
|
if (randomBoolean()) {
|
||||||
|
port = randomIntBetween(300, 400);
|
||||||
|
sb.put(HipChatServer.PORT_SETTING, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] defaultRooms = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultRooms = new String[] { "_r1", "_r2" };
|
||||||
|
sb.put(HipChatAccount.DEFAULT_ROOM_SETTING, "_r1,_r2");
|
||||||
|
}
|
||||||
|
String defaultFrom = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultFrom = randomAsciiOfLength(10);
|
||||||
|
sb.put(HipChatAccount.DEFAULT_FROM_SETTING, defaultFrom);
|
||||||
|
}
|
||||||
|
HipChatMessage.Format defaultFormat = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultFormat = randomFrom(HipChatMessage.Format.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_FORMAT_SETTING, defaultFormat);
|
||||||
|
}
|
||||||
|
HipChatMessage.Color defaultColor = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultColor = randomFrom(HipChatMessage.Color.values());
|
||||||
|
sb.put(HipChatAccount.DEFAULT_COLOR_SETTING, defaultColor);
|
||||||
|
}
|
||||||
|
Boolean defaultNotify = null;
|
||||||
|
if (randomBoolean()) {
|
||||||
|
defaultNotify = randomBoolean();
|
||||||
|
sb.put(HipChatAccount.DEFAULT_NOTIFY_SETTING, defaultNotify);
|
||||||
|
}
|
||||||
|
Settings settings = sb.build();
|
||||||
|
|
||||||
|
V1Account account = new V1Account(accountName, settings, HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
|
||||||
|
assertThat(account.profile, is(HipChatAccount.Profile.V1));
|
||||||
|
assertThat(account.name, equalTo(accountName));
|
||||||
|
assertThat(account.server.host(), is(host));
|
||||||
|
assertThat(account.server.port(), is(port));
|
||||||
|
assertThat(account.authToken, is(authToken));
|
||||||
|
if (defaultRooms != null) {
|
||||||
|
assertThat(account.defaults.rooms, arrayContaining(defaultRooms));
|
||||||
|
} else {
|
||||||
|
assertThat(account.defaults.rooms, nullValue());
|
||||||
|
}
|
||||||
|
assertThat(account.defaults.from, is(defaultFrom));
|
||||||
|
assertThat(account.defaults.format, is(defaultFormat));
|
||||||
|
assertThat(account.defaults.color, is(defaultColor));
|
||||||
|
assertThat(account.defaults.notify, is(defaultNotify));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = SettingsException.class)
|
||||||
|
public void testSettings_NoAuthToken() throws Exception {
|
||||||
|
Settings.Builder sb = Settings.builder();
|
||||||
|
new V1Account("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(ESLogger.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSend() throws Exception {
|
||||||
|
HttpClient httpClient = mock(HttpClient.class);
|
||||||
|
V1Account account = new V1Account("_name", Settings.builder()
|
||||||
|
.put("host", "_host")
|
||||||
|
.put("port", "443")
|
||||||
|
.put("auth_token", "_token")
|
||||||
|
.build(), HipChatServer.DEFAULT, httpClient, mock(ESLogger.class));
|
||||||
|
|
||||||
|
HipChatMessage.Format format = randomFrom(HipChatMessage.Format.values());
|
||||||
|
HipChatMessage.Color color = randomFrom(HipChatMessage.Color.values());
|
||||||
|
Boolean notify = randomBoolean();
|
||||||
|
HipChatMessage message = new HipChatMessage("_body", new String[] { "_r1", "_r2" }, null, "_from", format, color, notify);
|
||||||
|
|
||||||
|
HttpRequest req1 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v1/rooms/message")
|
||||||
|
.setHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.setParam("format", "json")
|
||||||
|
.setParam("auth_token", "_token")
|
||||||
|
.body(new StringBuilder()
|
||||||
|
.append("room_id=").append("_r1&")
|
||||||
|
.append("from=").append("_from&")
|
||||||
|
.append("message=").append("_body&")
|
||||||
|
.append("message_format=").append(format.value()).append("&")
|
||||||
|
.append("color=").append(color.value()).append("&")
|
||||||
|
.append("notify=").append(notify ? "1" : "0")
|
||||||
|
.toString())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (r1): " + jsonBuilder().value(req1).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse res1 = mock(HttpResponse.class);
|
||||||
|
when(res1.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(req1)).thenReturn(res1);
|
||||||
|
|
||||||
|
HttpRequest req2 = HttpRequest.builder("_host", 443)
|
||||||
|
.method(HttpMethod.POST)
|
||||||
|
.scheme(Scheme.HTTPS)
|
||||||
|
.path("/v1/rooms/message")
|
||||||
|
.setHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.setParam("format", "json")
|
||||||
|
.setParam("auth_token", "_token")
|
||||||
|
.body(new StringBuilder()
|
||||||
|
.append("room_id=").append("_r2&")
|
||||||
|
.append("from=").append("_from&")
|
||||||
|
.append("message=").append("_body&")
|
||||||
|
.append("message_format=").append(format.value()).append("&")
|
||||||
|
.append("color=").append(color.value()).append("&")
|
||||||
|
.append("notify=").append(notify ? "1" : "0")
|
||||||
|
.toString())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
logger.info("expected (r2): " + jsonBuilder().value(req2).bytes().toUtf8());
|
||||||
|
|
||||||
|
HttpResponse res2 = mock(HttpResponse.class);
|
||||||
|
when(res2.status()).thenReturn(200);
|
||||||
|
when(httpClient.execute(req2)).thenReturn(res2);
|
||||||
|
|
||||||
|
account.send(message);
|
||||||
|
|
||||||
|
verify(httpClient).execute(req1);
|
||||||
|
verify(httpClient).execute(req2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
import org.elasticsearch.plugins.PluginsService;
|
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
|
|
|
@ -327,6 +327,7 @@ public abstract class AbstractWatcherIntegrationTests extends ESIntegTestCase {
|
||||||
assertWatchWithMinimumPerformedActionsCount(watchName, minimumExpectedWatchActionsWithActionPerformed, true);
|
assertWatchWithMinimumPerformedActionsCount(watchName, minimumExpectedWatchActionsWithActionPerformed, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO remove this shitty method... the `assertConditionMet` is bogus
|
||||||
protected void assertWatchWithMinimumPerformedActionsCount(final String watchName, final long minimumExpectedWatchActionsWithActionPerformed, final boolean assertConditionMet) throws Exception {
|
protected void assertWatchWithMinimumPerformedActionsCount(final String watchName, final long minimumExpectedWatchActionsWithActionPerformed, final boolean assertConditionMet) throws Exception {
|
||||||
final AtomicReference<SearchResponse> lastResponse = new AtomicReference<>();
|
final AtomicReference<SearchResponse> lastResponse = new AtomicReference<>();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.watcher.test.integration;
|
package org.elasticsearch.watcher.test.integration;
|
||||||
|
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||||
|
|
Loading…
Reference in New Issue