Remove Hipchat support from Watcher (#39374)

* Remove Hipchat support from Watcher (#39199)

Hipchat has been shut down and has previously been deprecated in
Watcher (#39160), therefore we should remove support for these actions.

* Add migrate note
This commit is contained in:
Lee Hinman 2019-02-25 15:08:46 -07:00 committed by GitHub
parent d5046b1c25
commit 7b8178c839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 19 additions and 4328 deletions

View File

@ -75,3 +75,9 @@ Tribe node functionality has been removed in favor of
* The method `DiscoveryPlugin#getDiscoveryTypes()` was removed, so that plugins
can no longer provide their own discovery implementations.
[float]
==== Watcher 'hipchat' action removed
Hipchat has been deprecated and shut down as a service. The `hipchat` action for
watches has been removed.

View File

@ -7,7 +7,6 @@
You configure {watcher} settings to set up {watcher} and send notifications via
<<email-notification-settings,email>>,
<<hipchat-notification-settings,HipChat>>,
<<slack-notification-settings,Slack>>, and
<<pagerduty-notification-settings, PagerDuty>>.
@ -67,10 +66,10 @@ Specifies the maximum size an HTTP response is allowed to have, defaults to
`xpack.http.whitelist`::
A list of URLs, that the internal HTTP client is allowed to connect to. This
client is used in the HTTP input, the webhook, the slack, pagerduty, hipchat
client is used in the HTTP input, the webhook, the slack, pagerduty,
and jira actions. This setting can be updated dynamically. It defaults to `*`
allowing everything. Note: If you configure this setting and you are using one
of the slack/pagerduty/hipchat actions, you have to ensure that the
of the slack/pagerduty actions, you have to ensure that the
corresponding endpoints are whitelisted as well.
[[ssl-notification-settings]]
@ -207,54 +206,6 @@ HTML feature groups>>.
Set to `false` to completely disable HTML sanitation. Not recommended.
Defaults to `true`.
[float]
[[hipchat-notification-settings]]
==== HipChat Notification Settings
You can configure the following HipChat notification settings in
`elasticsearch.yml`. For more information about sending notifications
via HipChat, see {xpack-ref}/actions-hipchat.html#configuring-hipchat-actions[Configuring HipChat].
`xpack.notification.hipchat` ::
Specifies account information for sending notifications
via HipChat. You can specify the following HipChat account attributes:
[[hipchat-account-attributes]]
`profile`;;
The HipChat account profile to use: `integration`,
`user`, or `v1`. Required.
`secure_auth_token` (<<secure-settings,Secure>>);;
The authentication token to use to access the HipChat API. Required.
`host`;;
The HipChat server hostname. Defaults to `api.hipchat.com`.
`port`;;
The HipChat server port number. Defaults to 443.
`room`;;
The room you want to send messages to. Must be specified
if the `profile` is set to `integration`. Not valid for
the `user` or `vi` profiles.
`user`;;
The HipChat user account to use to send messages.
Specified as an email address. Must be specified if the
`profile` is set to `user`. Not valid for the `integration`
or `v1` profiles.
`message.format`;;
The format of the message: `text` or `html`.
Defaults to `html`.
`message.color`;;
The background color of the notification in the room.
Defaults to `yellow`.
`message.notify`;;
Indicates whether people in the room should be
actively notified. Defaults to `false`.
[float]
[[slack-notification-settings]]
==== Slack Notification Settings

View File

@ -16,8 +16,8 @@ serve as a model for a templated email body.
{watcher} supports the following types of actions:
<<actions-email, email>>, <<actions-webhook, webhook>>, <<actions-index, index>>,
<<actions-logging, logging>>, <<actions-hipchat, hipchat>>, <<actions-slack,
Slack>>, and <<actions-pagerduty, pagerduty>>.
<<actions-logging, logging>>, <<actions-slack, Slack>>,
and <<actions-pagerduty, pagerduty>>.
[float]
[[actions-ack-throttle]]
@ -271,9 +271,6 @@ include::actions/index.asciidoc[]
:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/watcher/actions/logging.asciidoc
include::actions/logging.asciidoc[]
:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/watcher/actions/hipchat.asciidoc
include::actions/hipchat.asciidoc[]
:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/watcher/actions/slack.asciidoc
include::actions/slack.asciidoc[]
@ -292,7 +289,7 @@ that even despite the exact same version, an OpenJDK distribution contains
different parts under different Linux distributions.
This can lead to issues with any action or input that uses TLS, like the `jira`,
`pagerduty`, `slack`, `hipchat` or `webhook` one, because of missing CA certs.
`pagerduty`, `slack`, or `webhook` one, because of missing CA certs.
If you encounter TLS errors, when writing watches that connect to TLS endpoints,
you should try to upgrade to the latest available OpenJDK distribution for your
platform and if that does not help, try to upgrade to Oracle JDK.

View File

@ -1,393 +0,0 @@
[[actions-hipchat]]
=== HipChat Action
Use the `hipchat` action to send messages to https://www.hipchat.com[HipChat]
rooms or users. To send HipChat messages, you must
<<configuring-hipchat, configure at least one HipChat account>> in `elasticsearch.yml`.
[[configuring-hipchat-actions]]
==== Configuring HipChat Actions
You configure HipChat actions in a `actions` array. Action-specific attributes
are specified using the `hipchat` keyword. You must specify the `message`
attribute for all `hipchat` actions. If you omit the `account` attribute, the
message is sent using the default HipChat account configured in
`elasticsearch.yml`.
For example, the following action is configured to send messages using a HipChat
account that uses the <<hipchat-api-integration, integration>> profile. Because
this type of account can only send messages to a specific room, the only required
attribute is the message itself:
[source,js]
--------------------------------------------------
"actions" : {
"notify-hipchat" : {
"transform" : { ... },
"throttle_period" : "5m",
"hipchat" : {
"account" : "integration-account", <1>
"message" : {
"body" : "Encountered {{ctx.payload.hits.total.value}} errors in the last 5 minutes (facepalm)", <2>
"format" : "text",
"color" : "red",
"notify" : true
}
}
}
}
--------------------------------------------------
// NOTCONSOLE
<1> The name of a HipChat account configured in `elasticsearch.yml`.
<2> The message you want to send to HipChat.
To send messages with a HipChat account that uses the <<hipchat-api-user, user>>
profile, you need to specify what rooms and users you want to send the message to.
For example, the following action is configured to send messages to the
`mission-control` and `devops` rooms as well as the user `website-admin@example.com`.
(To send to multiple users or rooms, specify an array of strings):
[source,js]
--------------------------------------------------
"actions" : {
"notify-hipchat" : {
"transform" : { ... },
"throttle_period" : "5m",
"hipchat" : {
"account" : "user-account",
"message" : {
"room" : [ "mission-control", "devops" ],
"user" : "website-admin@example.com",
"body" : "Encountered {{ctx.payload.hits.total.value}} errors in the last 5 minutes (facepalm)",
"format" : "text",
"color" : "red",
"notify" : true
}
}
}
}
--------------------------------------------------
// NOTCONSOLE
To send messages with a HipChat account that uses the <<hipchat-api-v1, v1>>
profile, you need to specify what room or rooms you want to send the message to.
For example, the following action is configured to send messages to the
`server-status` room. (To send to multiple rooms, specify an array of strings.)
[source,js]
--------------------------------------------------
"actions" : {
"notify-hipchat" : {
"transform" : { ... },
"throttle_period" : "5m",
"hipchat" : {
"account" : "v1-account",
"message" : {
"from" : "Watcher",
"room" : [ "server-status", "infra-team" ],
"body" : "Encountered {{ctx.payload.hits.total.value}} errors in the last 5 minutes (facepalm)",
"format" : "text",
"color" : "red",
"notify" : true
}
}
}
}
--------------------------------------------------
// NOTCONSOLE
[[hipchat-action-attributes]]
==== HipChat Action Attributes
[cols=",^,,", options="header"]
|======
| Name |Required | Default | Description
| `account` | no | Default account | The HipChat account to use to send the message.
| `proxy.host` | no | - | The proxy host to use (only in combination with `proxy.port`)
| `proxy.port` | no | - | The proxy port to use (only in combination with `proxy.host`)
| `message.body` | yes | - | The message content. Can contain up to 1000 characters.
| `message.format` | no | html | The format of the message: `text` or `html`.
| `message.color` | no | yellow | The background color of the notification in the room:
`gray`, `green`, `purple`, `red`, `yellow`.
| `message.notify` | no | false | Indicates whether people in the room should be actively
notified
| `message.from` | no | the watch ID | The name that appears as the notification sender. Only
valid for accounts that use the v1 profile.
| `message.room` | no | - | The rooms that the notification should go to. Accepts
a string value or an array of string values. Must be
specified when using the v1 profile. At least one room
or user must be specified when using the `user` profile.
Not valid for the `integration` profile.
| `message.user` | no | - | The users that the notification should go to. Accepts
a string value or an array of string values. At least
one room or user must be specified when using the `user`
profile. Not valid for the `integration` or `v1` profiles.
|======
[[configuring-hipchat]]
==== Configuring HipChat Accounts
You configure the accounts {watcher} can use to communicate with HipChat in the
`xpack.notification.hipchat` namespace in `elasticsearch.yml`. Both
https://www.hipchat.com/docs/api[v1] and
https://www.hipchat.com/docs/apiv2[v2] HipChat APIs are supported.
{watcher} provides three HipChat API profiles:
<<hipchat-api-integration,integration>>::
Sends messages to a specific room using HipChat's v2 API
https://www.hipchat.com/docs/apiv2/method/send_room_notification[Send room
notification].
<<hipchat-api-user, user>>::
Sends messages as a particular user through the HipChat v2 API. Enables you to
send messages to arbitrary rooms or users.
<<hipchat-api-v1, v1>>::
Sends messages to rooms using HipChat's v1 API
https://www.hipchat.com/docs/api/method/rooms/message[rooms/message].
+
NOTE: The `v1` profile is provided because it is simple to set up and this API
is familiar to many users. That said, HipChat has deprecated the v1 API
and is encouraging users to migrate to v2. Both the `integration` and
`user` profiles are based on the HipChat v2 API.
If you configure multiple HipChat accounts, you either need to set a default
HipChat account or specify which account the notification should be sent with
in the <<actions-hipchat, hipchat>> action.
deprecated[Storing the `auth_token` in the configuration file or using via updating the settings now is deprecated, as you should use the keystore for this, see {ref}/secure-settings.html[secure settings]]
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
default_account: team1
account:
team1:
...
team2:
...
--------------------------------------------------
[[hipchat-api-integration]]
===== Using the Hipchat Integration Profile
You can use the `integration` profile to send messages to specific rooms. When
you set an account's profile to `integration`, the messages are sent through
HipChat's v2 https://www.hipchat.com/docs/apiv2/method/send_room_notification[
Send room notification] API.
When you use the `integration` profile, you need to configure a separate HipChat
account for each room you want to send messages--the account configuration
contains a room-specific authentication token. Alternatively, you can use the
<<hipchat-api-user, `user`>> or <<hipchat-api-v1, `v1`>> profile to send messages
to multiple rooms.
NOTE: The `integration` profile only supports sending messages to rooms, it does
not support sending private messages. Use the <<hipchat-api-user, `user`>>
profile to notify a particular HipChat user.
You need a room-specific authentication token to configure an `integration`
account. To generate an authentication token:
. Log in to http://hipchat.com[hipchat.com] or your HipChat server as a group
administrator.
. Go to *Group admin > Rooms*.
. Click the name of the room you want to send messages to.
. Click the *Tokens* link.
. Enter a name for the token in the *Label* field.
+
image::images/hipchat-generate-room-token.jpg[]
. Select the *Send Notification* scope.
. Click *Create*.
. Copy the generated token so you can paste it into your HipChat account
configuration in `elasticsearch.yml`.
+
image::images/hipchat-copy-room-token.jpg[]
To configure a HipChat account that uses the `integration` profile:
. Set the `type` to `integration`.
. Set `room` to the name of the room you want to send messages to.
. Set `auth_token` to the room-specific authentication token.
For example, the following snippet configures an account called
`notify-monitoring` that sends messages to the `monitoring` room:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: integration
room: monitoring
--------------------------------------------------
You can also specify defaults for the {ref}/notification-settings.html#hipchat-account-attributes[
message attributes]:
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: integration
room: monitoring
message:
format: text
color: blue
notify: true
--------------------------------------------------
[[hipchat-api-user]]
===== Using the HipChat User Profile
You can use the `user` profile to send messages to rooms as well as individual
HipChat users. When you set an account's profile to `user`, {watcher} sends
messages as a particular user through the HipChat v2 API.
Before you can configure a `user` account, you need to:
. Add a HipChat user for {watcher}. When setting the user name, keep in mind that
the messages are sent on behalf of this user.
. Create an API token for the {watcher} user:
.. Log in to HipChat as the {watcher} user.
.. Go to `https://<hipchat-server>/account/api`. For example,
`https://www.hipchat.com/account/api`.
.. Confirm the user password.
.. Enter a name for the token in the *Label* field.
+
image::images/hipchat-generate-user-token.jpg[]
. Select the *Send Notification* and *Send Message* scopes.
. Click *Create*.
. Copy the generated token so you can paste it into your HipChat account
configuration in `elasticsearch.yml`.
+
image::images/hipchat-copy-room-token.jpg[]
To configure a HipChat account that uses the `user` profile:
. Set the `type` to `user`.
. Set `user` to the email address associated with the {watcher} user.
. Set `auth_token` to the {watcher} user's authentication token.
For example, the following configuration creates an account called
`notify-monitoring` that sends messages to the `monitoring` room:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: user
--------------------------------------------------
You can also specify defaults for the <{ref}/notification-settings.html#hipchat-account-attributes[
message attributes]:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: user
message:
format: text
color: blue
notify: true
--------------------------------------------------
[[hipchat-api-v1]]
===== Using the HipChat v1 Profile
You can use the `v1` profile to send messages to particular rooms. When you set
an account's profile to `v1`, messages are sent through HipChat's v1
https://www.hipchat.com/docs/api/method/rooms/message[rooms/message] API.
WARNING: The `v1` profile uses a deprecated API that is expected to be removed
by HipChat in the future.
The `v1` profile only supports sending messages to rooms, it does not support
sending private messages. Use the <<hipchat-api-user, `user`>> profile to send
private messages to HipChat users.
Before you can configure a `v1` account, you need to generate a `v1` API token:
. Log in to your HipChat server as a group admin.
. Go to `https://<hipchat-server>/admin/api`. For example,
`https://hipchat.com/admin/api`.
. Confirm your admin password.
. Select the *Notification* type.
+
image::images/hipchat-generate-v1-token.jpg[]
. Enter a name for the token in the *Label* field.
. Click *Create*.
. Copy the generated token so you can paste it into your HipChat account
configuration in `elasticsearch.yml`.
+
image::images/hipchat-copy-v1-token.jpg[]
To configure a HipChat account that uses the `v1` profile:
. Set the `type` to `v1`.
. Set `auth_token` to the v1 authentication token you generated.
For example, the following configuration creates an account called
`notify-monitoring`:
[source,shell]
--------------------------------------------------
bin/elasticsearch-keystore add xpack.notification.hipchat.account.notify-monitoring.secure_auth_token
--------------------------------------------------
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: v1
--------------------------------------------------
You can also specify defaults for the {ref}/notification-settings.html#hipchat-account-attributes[
message attributes].
[source,yaml]
--------------------------------------------------
xpack.notification.hipchat:
account:
notify-monitoring:
profile: v1
message:
format: text
color: blue
notify: true
--------------------------------------------------

View File

@ -202,7 +202,7 @@ Actions are associated with a watch and are executed as part of the watch execut
only when the watch condition is met.
{watcher} supports the following action types: <<actions-email, email>>,
<<actions-slack, slack>>, <<actions-hipchat, hipchat>>, <<actions-pagerduty, pagerduty>>,
<<actions-slack, slack>>, <<actions-pagerduty, pagerduty>>,
<<actions-index, index>>, <<actions-logging, logging>>, and <<actions-webhook, webhook>>.
To use the `email` action, you need to <<configuring-email, configure an email account>>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

View File

@ -333,63 +333,6 @@
}
}
},
"hipchat" : {
"type": "object",
"dynamic": true,
"properties": {
"account": {
"type": "keyword"
},
"sent_messages": {
"type": "nested",
"include_in_parent": true,
"dynamic": true,
"properties": {
"status": {
"type": "keyword"
},
"reason": {
"type": "text"
},
"request" : {
"type" : "object",
"enabled" : false
},
"response" : {
"type" : "object",
"enabled" : false
},
"room" : {
"type": "keyword"
},
"user" : {
"type": "keyword"
},
"message" : {
"type" : "object",
"dynamic" : true,
"properties" : {
"message_format" : {
"type" : "keyword"
},
"color" : {
"type" : "keyword"
},
"notify" : {
"type" : "boolean"
},
"message" : {
"type" : "text"
},
"from" : {
"type" : "text"
}
}
}
}
}
}
},
"jira" : {
"type": "object",
"dynamic": true,

View File

@ -82,8 +82,6 @@ import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
import org.elasticsearch.xpack.core.watcher.watch.Watch;
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatActionFactory;
import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
import org.elasticsearch.xpack.watcher.actions.index.IndexActionFactory;
import org.elasticsearch.xpack.watcher.actions.jira.JiraAction;
@ -135,7 +133,6 @@ import org.elasticsearch.xpack.watcher.notification.email.attachment.EmailAttach
import org.elasticsearch.xpack.watcher.notification.email.attachment.HttpEmailAttachementParser;
import org.elasticsearch.xpack.watcher.notification.email.attachment.ReportingAttachmentParser;
import org.elasticsearch.xpack.watcher.notification.email.support.BodyPartSource;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatService;
import org.elasticsearch.xpack.watcher.notification.jira.JiraService;
import org.elasticsearch.xpack.watcher.notification.pagerduty.PagerDutyService;
import org.elasticsearch.xpack.watcher.notification.slack.SlackService;
@ -277,13 +274,11 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
// notification
EmailService emailService = new EmailService(settings, cryptoService, clusterService.getClusterSettings());
HipChatService hipChatService = new HipChatService(settings, httpClient, clusterService.getClusterSettings());
JiraService jiraService = new JiraService(settings, httpClient, clusterService.getClusterSettings());
SlackService slackService = new SlackService(settings, httpClient, clusterService.getClusterSettings());
PagerDutyService pagerDutyService = new PagerDutyService(settings, httpClient, clusterService.getClusterSettings());
reloadableServices.add(emailService);
reloadableServices.add(hipChatService);
reloadableServices.add(jiraService);
reloadableServices.add(slackService);
reloadableServices.add(pagerDutyService);
@ -315,7 +310,6 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
actionFactoryMap.put(WebhookAction.TYPE, new WebhookActionFactory(httpClient, templateEngine));
actionFactoryMap.put(IndexAction.TYPE, new IndexActionFactory(settings, client));
actionFactoryMap.put(LoggingAction.TYPE, new LoggingActionFactory(templateEngine));
actionFactoryMap.put(HipChatAction.TYPE, new HipChatActionFactory(templateEngine, hipChatService));
actionFactoryMap.put(JiraAction.TYPE, new JiraActionFactory(templateEngine, jiraService));
actionFactoryMap.put(SlackAction.TYPE, new SlackActionFactory(templateEngine, slackService));
actionFactoryMap.put(PagerDutyAction.TYPE, new PagerDutyActionFactory(templateEngine, pagerDutyService));
@ -420,7 +414,7 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
return Arrays.asList(registry, inputRegistry, historyStore, triggerService, triggeredWatchParser,
watcherLifeCycleService, executionService, triggerEngineListener, watcherService, watchParser,
configuredTriggerEngine, triggeredWatchStore, watcherSearchTemplateService, slackService, pagerDutyService, hipChatService);
configuredTriggerEngine, triggeredWatchStore, watcherSearchTemplateService, slackService, pagerDutyService);
}
protected TriggerEngine getTriggerEngine(Clock clock, ScheduleRegistry scheduleRegistry) {
@ -481,7 +475,6 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa
settings.addAll(SlackService.getSettings());
settings.addAll(EmailService.getSettings());
settings.addAll(HtmlSanitizer.getSettings());
settings.addAll(HipChatService.getSettings());
settings.addAll(JiraService.getSettings());
settings.addAll(PagerDutyService.getSettings());
settings.add(ReportingAttachmentParser.RETRIES_SETTING);

View File

@ -6,19 +6,18 @@
package org.elasticsearch.xpack.watcher.actions;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.xpack.watcher.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.notification.email.EmailTemplate;
import org.elasticsearch.xpack.watcher.notification.pagerduty.IncidentEvent;
import org.elasticsearch.xpack.watcher.notification.slack.message.SlackMessage;
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
import org.elasticsearch.xpack.watcher.actions.jira.JiraAction;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction;
import org.elasticsearch.xpack.watcher.actions.pagerduty.PagerDutyAction;
import org.elasticsearch.xpack.watcher.actions.slack.SlackAction;
import org.elasticsearch.xpack.watcher.actions.webhook.WebhookAction;
import org.elasticsearch.xpack.watcher.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.notification.email.EmailTemplate;
import org.elasticsearch.xpack.watcher.notification.pagerduty.IncidentEvent;
import org.elasticsearch.xpack.watcher.notification.slack.message.SlackMessage;
import java.util.Map;
@ -63,22 +62,6 @@ public final class ActionBuilders {
return LoggingAction.builder(text);
}
public static HipChatAction.Builder hipchatAction(String message) {
return hipchatAction(new TextTemplate(message));
}
public static HipChatAction.Builder hipchatAction(String account, String body) {
return hipchatAction(account, new TextTemplate(body));
}
public static HipChatAction.Builder hipchatAction(TextTemplate body) {
return hipchatAction(null, body);
}
public static HipChatAction.Builder hipchatAction(String account, TextTemplate body) {
return HipChatAction.builder(account, body);
}
public static SlackAction.Builder slackAction(String account, SlackMessage.Template.Builder message) {
return slackAction(account, message.build());
}

View File

@ -1,53 +0,0 @@
/*
* 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.xpack.watcher.actions.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.actions.ExecutableAction;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatAccount;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatService;
import org.elasticsearch.xpack.watcher.notification.hipchat.SentMessages;
import org.elasticsearch.xpack.watcher.support.Variables;
import java.util.Map;
public class ExecutableHipChatAction extends ExecutableAction<HipChatAction> {
private final TextTemplateEngine templateEngine;
private final HipChatService hipchatService;
public ExecutableHipChatAction(HipChatAction action, Logger logger, HipChatService hipchatService,
TextTemplateEngine 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 = hipchatService.getAccount(action.account);
// 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.createCtxParamsMap(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, action.proxy);
return new HipChatAction.Result.Executed(sentMessages);
}
}

View File

@ -1,253 +0,0 @@
/*
* 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.xpack.watcher.actions.hipchat;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage;
import org.elasticsearch.xpack.watcher.notification.hipchat.SentMessages;
import java.io.IOException;
import java.util.Objects;
public class HipChatAction implements Action {
public static final String TYPE = "hipchat";
@Nullable final String account;
@Nullable final HttpProxy proxy;
final HipChatMessage.Template message;
public HipChatAction(@Nullable String account, HipChatMessage.Template message, @Nullable HttpProxy proxy) {
this.account = account;
this.message = message;
this.proxy = proxy;
}
@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;
return Objects.equals(account, that.account) &&
Objects.equals(message, that.message) &&
Objects.equals(proxy, that.proxy);
}
@Override
public int hashCode() {
return Objects.hash(account, message, proxy);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (account != null) {
builder.field(Field.ACCOUNT.getPreferredName(), account);
}
if (proxy != null) {
proxy.toXContent(builder, params);
}
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;
HttpProxy proxy = 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 (Field.ACCOUNT.match(currentFieldName, parser.getDeprecationHandler())) {
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 (Field.PROXY.match(currentFieldName, parser.getDeprecationHandler())) {
proxy = HttpProxy.parse(parser);
} else if (Field.MESSAGE.match(currentFieldName, parser.getDeprecationHandler())) {
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, proxy);
}
public static Builder builder(String account, TextTemplate 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.isSuccess()) {
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;
private HttpProxy proxy;
public Builder(String account, TextTemplate body) {
this.account = account;
this.messageBuilder = new HipChatMessage.Template.Builder(body);
}
public Builder addRooms(TextTemplate... rooms) {
messageBuilder.addRooms(rooms);
return this;
}
public Builder addRooms(String... rooms) {
TextTemplate[] templates = new TextTemplate[rooms.length];
for (int i = 0; i < rooms.length; i++) {
templates[i] = new TextTemplate(rooms[i]);
}
return addRooms(templates);
}
public Builder addUsers(TextTemplate... users) {
messageBuilder.addUsers(users);
return this;
}
public Builder addUsers(String... users) {
TextTemplate[] templates = new TextTemplate[users.length];
for (int i = 0; i < users.length; i++) {
templates[i] = new TextTemplate(users[i]);
}
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(TextTemplate color) {
messageBuilder.setColor(color);
return this;
}
public Builder setColor(HipChatMessage.Color color) {
return setColor(color.asTemplate());
}
public Builder setNotify(boolean notify) {
messageBuilder.setNotify(notify);
return this;
}
public Builder setProxy(HttpProxy proxy) {
this.proxy = proxy;
return this;
}
@Override
public HipChatAction build() {
return new HipChatAction(account, messageBuilder.build(), proxy);
}
}
public interface Field {
ParseField ACCOUNT = new ParseField("account");
ParseField MESSAGE = new ParseField("message");
ParseField PROXY = new ParseField("proxy");
}
}

View File

@ -1,35 +0,0 @@
/*
* 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.xpack.watcher.actions.hipchat;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.watcher.actions.ActionFactory;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatAccount;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatService;
import java.io.IOException;
public class HipChatActionFactory extends ActionFactory {
private final TextTemplateEngine templateEngine;
private final HipChatService hipchatService;
public HipChatActionFactory(TextTemplateEngine templateEngine, HipChatService hipchatService) {
super(LogManager.getLogger(ExecutableHipChatAction.class));
this.templateEngine = templateEngine;
this.hipchatService = hipchatService;
}
@Override
public ExecutableHipChatAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
HipChatAction action = HipChatAction.parse(watchId, actionId, parser);
HipChatAccount account = hipchatService.getAccount(action.account);
account.validateParsedTemplate(watchId, actionId, action.message);
return new ExecutableHipChatAction(action, actionLogger, hipchatService, templateEngine);
}
}

View File

@ -300,7 +300,7 @@ public class HttpClient implements Closeable {
Scheme.parse(HttpSettings.PROXY_SCHEME.get(settings)) : Scheme.HTTP;
int proxyPort = HttpSettings.PROXY_PORT.get(settings);
if (proxyPort != 0 && Strings.hasText(proxyHost)) {
logger.info("Using default proxy for http input and slack/hipchat/pagerduty/webhook actions [{}:{}]", proxyHost, proxyPort);
logger.info("Using default proxy for http input and slack/pagerduty/webhook actions [{}:{}]", proxyHost, proxyPort);
} else if (proxyPort != 0 ^ Strings.hasText(proxyHost)) {
throw new IllegalArgumentException("HTTP proxy requires both settings: [" + HttpSettings.PROXY_HOST.getKey() + "] and [" +
HttpSettings.PROXY_PORT.getKey() + "]");

View File

@ -1,126 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
public abstract class HipChatAccount {
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();
static final Setting<SecureString> SECURE_AUTH_TOKEN_SETTING = SecureSetting.secureString("secure_auth_token", null);
protected final Logger 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,
Logger logger) {
this.name = name;
this.profile = profile;
this.server = new HipChatServer(settings, defaultServer);
this.httpClient = httpClient;
this.authToken = getAuthToken(name, settings);
this.logger = logger;
}
private static String getAuthToken(String name, Settings settings) {
SecureString secureString = SECURE_AUTH_TOKEN_SETTING.get(settings);
if (secureString == null || secureString.length() < 1) {
throw new SettingsException(
"hipchat account [" + name + "] missing required [" + SECURE_AUTH_TOKEN_SETTING.getKey() + "] secure setting");
}
return secureString.toString();
}
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, TextTemplateEngine engine, HipChatMessage.Template template,
Map<String, Object> model);
public abstract SentMessages send(HipChatMessage message, @Nullable HttpProxy proxy);
public enum Profile {
V1() {
@Override
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient,
Logger logger) {
return new V1Account(name, settings, defaultServer, httpClient, logger);
}
},
INTEGRATION() {
@Override
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient,
Logger logger) {
return new IntegrationAccount(name, settings, defaultServer, httpClient, logger);
}
},
USER() {
@Override
HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient,
Logger logger) {
return new UserAccount(name, settings, defaultServer, httpClient, logger);
}
};
abstract HipChatAccount createAccount(String name, Settings settings, HipChatServer defaultServer, HttpClient httpClient,
Logger logger);
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;
}
}
}
}

View File

@ -1,457 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
public class HipChatMessage implements ToXContentObject {
final String body;
@Nullable final String[] rooms;
@Nullable final String[] users;
@Nullable final String from;
@Nullable final Format format;
@Nullable final Color color;
@Nullable final 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;
return Objects.equals(body, that.body) &&
Objects.deepEquals(rooms, that.rooms) &&
Objects.deepEquals(users, that.users) &&
Objects.equals(from, that.from) &&
Objects.equals(format, that.format) &&
Objects.equals(color, that.color) &&
Objects.equals(notify, that.notify);
}
@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.value());
}
if (color != null) {
builder.field(Field.COLOR.getPreferredName(), color.value());
}
if (notify != null) {
builder.field(Field.NOTIFY.getPreferredName(), notify);
}
return builder.endObject();
}
public static class Template implements ToXContentObject {
final TextTemplate body;
@Nullable final TextTemplate[] rooms;
@Nullable final TextTemplate[] users;
@Nullable final String from;
@Nullable final Format format;
@Nullable final TextTemplate color;
@Nullable final Boolean notify;
public Template(TextTemplate body,
TextTemplate[] rooms,
TextTemplate[] users,
String from,
Format format,
TextTemplate 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;
return Objects.equals(body, template.body) &&
Objects.deepEquals(rooms, template.rooms) &&
Objects.deepEquals(users, template.users) &&
Objects.equals(from, template.from) &&
Objects.equals(format, template.format) &&
Objects.equals(color, template.color) &&
Objects.equals(notify, template.notify);
}
@Override
public int hashCode() {
return Objects.hash(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 (TextTemplate room : rooms) {
room.toXContent(builder, params);
}
builder.endArray();
}
if (users != null && users.length > 0) {
builder.startArray(Field.USER.getPreferredName());
for (TextTemplate user : users) {
user.toXContent(builder, params);
}
builder.endArray();
}
builder.field(Field.BODY.getPreferredName(), body, params);
if (format != null) {
builder.field(Field.FORMAT.getPreferredName(), format.value());
}
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 {
TextTemplate body = null;
TextTemplate[] rooms = null;
TextTemplate[] users = null;
String from = null;
TextTemplate 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 (Field.FROM.match(currentFieldName, parser.getDeprecationHandler())) {
from = parser.text();
} else if (Field.ROOM.match(currentFieldName, parser.getDeprecationHandler())) {
List<TextTemplate> templates = new ArrayList<>();
if (token == XContentParser.Token.START_ARRAY) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
try {
templates.add(TextTemplate.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(TextTemplate.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 TextTemplate[templates.size()]);
} else if (Field.USER.match(currentFieldName, parser.getDeprecationHandler())) {
List<TextTemplate> templates = new ArrayList<>();
if (token == XContentParser.Token.START_ARRAY) {
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
try {
templates.add(TextTemplate.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(TextTemplate.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 TextTemplate[templates.size()]);
} else if (Field.COLOR.match(currentFieldName, parser.getDeprecationHandler())) {
try {
color = TextTemplate.parse(parser);
} catch (ElasticsearchParseException | IllegalArgumentException e) {
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", e,
Field.COLOR.getPreferredName());
}
} else if (Field.NOTIFY.match(currentFieldName, parser.getDeprecationHandler())) {
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 (Field.BODY.match(currentFieldName, parser.getDeprecationHandler())) {
try {
body = TextTemplate.parse(parser);
} catch (ElasticsearchParseException pe) {
throw new ElasticsearchParseException("failed to parse hipchat message. failed to parse [{}] field", pe,
Field.BODY.getPreferredName());
}
} else if (Field.FORMAT.match(currentFieldName, parser.getDeprecationHandler())) {
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 field [{}]", currentFieldName);
}
}
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 TextTemplate body;
final List<TextTemplate> rooms = new ArrayList<>();
final List<TextTemplate> users = new ArrayList<>();
@Nullable String from;
@Nullable Format format;
@Nullable TextTemplate color;
@Nullable Boolean notify;
public Builder(TextTemplate body) {
this.body = body;
}
public Builder addRooms(TextTemplate... rooms) {
this.rooms.addAll(Arrays.asList(rooms));
return this;
}
public Builder addUsers(TextTemplate... 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(TextTemplate 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 TextTemplate[rooms.size()]),
users.isEmpty() ? null : users.toArray(new TextTemplate[users.size()]),
from,
format,
color,
notify);
}
}
}
public enum Color {
YELLOW, GREEN, RED, PURPLE, GRAY, RANDOM;
private final TextTemplate template = new TextTemplate(name());
public TextTemplate asTemplate() {
return template;
}
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 {
TEXT,
HTML;
private final TextTemplate template = new TextTemplate(name());
public TextTemplate asTemplate() {
return template;
}
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");
}
}

View File

@ -1,56 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.watcher.common.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());
}
}

View File

@ -1,111 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.SecureSetting;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.notification.NotificationService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A component to store hipchat credentials.
*/
public class HipChatService extends NotificationService<HipChatAccount> {
private static final Setting<String> SETTING_DEFAULT_ACCOUNT =
Setting.simpleString("xpack.notification.hipchat.default_account", Setting.Property.Dynamic, Setting.Property.NodeScope);
static final Setting<String> SETTING_DEFAULT_HOST =
Setting.simpleString("xpack.notification.hipchat.host", Setting.Property.Dynamic, Setting.Property.NodeScope);
static final Setting<Integer> SETTING_DEFAULT_PORT =
Setting.intSetting("xpack.notification.hipchat.port", 443, Setting.Property.Dynamic, Setting.Property.NodeScope);
private static final Setting.AffixSetting<SecureString> SETTING_AUTH_TOKEN_SECURE =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "secure_auth_token",
(key) -> SecureSetting.secureString(key, null));
private static final Setting.AffixSetting<String> SETTING_PROFILE =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "profile",
(key) -> Setting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope));
private static final Setting.AffixSetting<String> SETTING_ROOM =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "room",
(key) -> Setting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope));
private static final Setting.AffixSetting<String> SETTING_HOST =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "host",
(key) -> Setting.simpleString(key, Setting.Property.Dynamic, Setting.Property.NodeScope));
private static final Setting.AffixSetting<Integer> SETTING_PORT =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "port",
(key) -> Setting.intSetting(key, 443, Setting.Property.Dynamic, Setting.Property.NodeScope));
private static final Setting.AffixSetting<Settings> SETTING_MESSAGE_DEFAULTS =
Setting.affixKeySetting("xpack.notification.hipchat.account.", "message",
(key) -> Setting.groupSetting(key + ".", Setting.Property.Dynamic, Setting.Property.NodeScope));
private static final Logger logger = LogManager.getLogger(HipChatService.class);
private final HttpClient httpClient;
private HipChatServer defaultServer;
public HipChatService(Settings settings, HttpClient httpClient, ClusterSettings clusterSettings) {
super("hipchat", settings, clusterSettings, HipChatService.getDynamicSettings(), HipChatService.getSecureSettings());
this.httpClient = httpClient;
// ensure logging of setting changes
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_ACCOUNT, (s) -> {});
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_HOST, (s) -> {});
clusterSettings.addSettingsUpdateConsumer(SETTING_DEFAULT_PORT, (s) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_PROFILE, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_ROOM, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_HOST, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_PORT, (s, o) -> {}, (s, o) -> {});
clusterSettings.addAffixUpdateConsumer(SETTING_MESSAGE_DEFAULTS, (s, o) -> {}, (s, o) -> {});
// do an initial load
reload(settings);
}
@Override
public synchronized void reload(Settings settings) {
defaultServer = new HipChatServer(settings.getByPrefix("xpack.notification.hipchat."));
super.reload(settings);
}
@Override
protected HipChatAccount createAccount(String name, Settings accountSettings) {
HipChatAccount.Profile profile = HipChatAccount.Profile.resolve(accountSettings, "profile", null);
if (profile == null) {
throw new SettingsException("missing [profile] setting for hipchat account [" + name + "]");
}
return profile.createAccount(name, accountSettings, defaultServer, httpClient, logger);
}
private static List<Setting<?>> getDynamicSettings() {
return Arrays.asList(SETTING_DEFAULT_ACCOUNT, SETTING_PROFILE, SETTING_ROOM, SETTING_MESSAGE_DEFAULTS,
SETTING_DEFAULT_HOST, SETTING_DEFAULT_PORT, SETTING_HOST, SETTING_PORT);
}
private static List<Setting<?>> getSecureSettings() {
return Arrays.asList(SETTING_AUTH_TOKEN_SECURE);
}
public static List<Setting<?>> getSettings() {
List<Setting<?>> allSettings = new ArrayList<Setting<?>>(getDynamicSettings());
allSettings.addAll(getSecureSettings());
return allSettings;
}
}

View File

@ -1,135 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Color;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Format;
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, Logger logger) {
super(name, Profile.INTEGRATION, settings, defaultServer, httpClient, logger);
List<String> rooms = settings.getAsList(ROOM_SETTING, null);
if (rooms == null || rooms.isEmpty()) {
throw new SettingsException("invalid hipchat account [" + name + "]. missing required [" + ROOM_SETTING + "] setting for [" +
TYPE + "] account profile");
}
if (rooms.size() > 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.get(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, TextTemplateEngine 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, @Nullable HttpProxy proxy) {
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
HttpRequest request = buildRoomRequest(room, message, proxy);
try {
HttpResponse response = httpClient.execute(request);
sentMessages.add(SentMessages.SentMessage.responded(room, SentMessages.SentMessage.TargetType.ROOM, message, request,
response));
} catch (Exception e) {
sentMessages.add(SentMessages.SentMessage.error(room, SentMessages.SentMessage.TargetType.ROOM, message, e));
}
return new SentMessages(name, sentMessages);
}
private HttpRequest buildRoomRequest(String room, final HipChatMessage message, HttpProxy proxy) {
String urlEncodedRoom = HttpRequest.encodeUrl(room);
HttpRequest.Builder builder = server.httpRequest()
.method(HttpMethod.POST)
.scheme(Scheme.HTTPS)
.path("/v2/room/" + urlEncodedRoom + "/notification")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Bearer " + authToken)
.body(Strings.toString((xbuilder, params) -> {
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;
}));
if (proxy != null) {
builder.proxy(proxy);
}
return builder.build();
}
static class Defaults {
@Nullable final Format format;
@Nullable final Color color;
@Nullable final Boolean notify;
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);
}
}
}

View File

@ -1,153 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.xpack.core.watcher.support.xcontent.WatcherParams;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
public class SentMessages implements ToXContentObject, Iterable<SentMessages.SentMessage> {
private static final ParseField ACCOUNT = new ParseField("account");
private static final ParseField SENT_MESSAGES = new ParseField("sent_messages");
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(ACCOUNT.getPreferredName(), accountName);
builder.startArray(SENT_MESSAGES.getPreferredName());
for (SentMessage message : messages) {
message.toXContent(builder, params);
}
builder.endArray();
return builder.endObject();
}
public static class SentMessage implements ToXContentObject {
private static final ParseField STATUS = new ParseField("status");
private static final ParseField REQUEST = new ParseField("request");
private static final ParseField RESPONSE = new ParseField("response");
private static final ParseField MESSAGE = new ParseField("message");
public enum TargetType {
ROOM, USER;
final String fieldName = new String(name().toLowerCase(Locale.ROOT));
}
final String targetName;
final TargetType targetType;
final HipChatMessage message;
@Nullable final HttpRequest request;
@Nullable final HttpResponse response;
@Nullable final Exception exception;
public static SentMessage responded(String targetName, TargetType targetType, HipChatMessage message, HttpRequest request,
HttpResponse response) {
return new SentMessage(targetName, targetType, message, request, response, null);
}
public static SentMessage error(String targetName, TargetType targetType, HipChatMessage message, Exception e) {
return new SentMessage(targetName, targetType, message, null, null, e);
}
private SentMessage(String targetName, TargetType targetType, HipChatMessage message, HttpRequest request, HttpResponse response,
Exception exception) {
this.targetName = targetName;
this.targetType = targetType;
this.message = message;
this.request = request;
this.response = response;
this.exception = exception;
}
public HttpRequest getRequest() {
return request;
}
public HttpResponse getResponse() {
return response;
}
public Exception getException() {
return exception;
}
public boolean isSuccess() {
return response != null && response.status() >= 200 && response.status() < 300;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
boolean success = isSuccess();
builder.field(STATUS.getPreferredName(), success ? "success" : "failure");
if (success == false) {
if (request != null) {
if (WatcherParams.hideSecrets(params)) {
// this writes out the request to the byte array output stream with the correct excludes for hipchat
try (InputStream is = HttpRequest.filterToXContent(request, builder.contentType().xContent(),
params, "params.auth_token")) {
builder.rawField(REQUEST.getPreferredName(), is, builder.contentType());
}
} else {
builder.field(REQUEST.getPreferredName());
request.toXContent(builder, params);
}
}
if (response != null) {
builder.field(RESPONSE.getPreferredName());
response.toXContent(builder, params);
}
if (exception != null) {
ElasticsearchException.generateFailureXContent(builder, params, exception, true);
}
}
builder.field(targetType.fieldName, targetName);
builder.field(MESSAGE.getPreferredName());
message.toXContent(builder, params, false);
return builder.endObject();
}
}
}

View File

@ -1,192 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Color;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Format;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
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, Logger 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, TextTemplateEngine 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, HttpProxy proxy) {
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
if (message.rooms != null) {
for (String room : message.rooms) {
HttpRequest request = buildRoomRequest(room, message, proxy);
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, e));
}
}
}
if (message.users != null) {
for (String user : message.users) {
HttpRequest request = buildUserRequest(user, message, proxy);
try {
HttpResponse response = httpClient.execute(request);
sentMessages.add(SentMessages.SentMessage.responded(user, SentMessages.SentMessage.TargetType.USER, message, request,
response));
} catch (Exception e) {
logger.error("failed to execute hipchat api http request", e);
sentMessages.add(SentMessages.SentMessage.error(user, SentMessages.SentMessage.TargetType.USER, message, e));
}
}
}
return new SentMessages(name, sentMessages);
}
public HttpRequest buildRoomRequest(String room, final HipChatMessage message, HttpProxy proxy) {
String urlEncodedRoom = encodeRoom(room);
HttpRequest.Builder builder = server.httpRequest()
.method(HttpMethod.POST)
.scheme(Scheme.HTTPS)
.path("/v2/room/" + urlEncodedRoom + "/notification")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Bearer " + authToken)
.body(Strings.toString((xbuilder, params) -> {
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;
}));
if (proxy != null) {
builder.proxy(proxy);
}
return builder.build();
}
// this specific hipchat API does not accept application-form encoding, but requires real URL encoding
// spaces must not be replaced with a plus, but rather with %20
// this workaround ensures, that this happens
private String encodeRoom(String text) {
try {
return new URI("//", "", "", text, null).getRawQuery();
} catch (URISyntaxException e) {
throw new IllegalArgumentException("failed to URL encode text [" + text + "]", e);
}
}
public HttpRequest buildUserRequest(String user, final HipChatMessage message, HttpProxy proxy) {
HttpRequest.Builder builder = server.httpRequest()
.method(HttpMethod.POST)
.scheme(Scheme.HTTPS)
.path("/v2/user/" + user + "/message")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Bearer " + authToken)
.body(Strings.toString((xbuilder, params) -> {
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;
}));
if (proxy != null) {
builder.proxy(proxy);
}
return builder.build();
}
static class Defaults {
@Nullable final String[] rooms;
@Nullable final String[] users;
@Nullable final Format format;
@Nullable final Color color;
@Nullable final Boolean notify;
Defaults(Settings settings) {
List<String> rooms = settings.getAsList(DEFAULT_ROOM_SETTING, null);
this.rooms = rooms == null ? null : rooms.toArray(Strings.EMPTY_ARRAY);
List<String> users = settings.getAsList(DEFAULT_USER_SETTING, null);
this.users = users == null ? null : users.toArray(Strings.EMPTY_ARRAY);
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);
}
}
}

View File

@ -1,139 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Color;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage.Format;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
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, Logger 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, TextTemplateEngine 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, @Nullable HttpProxy proxy) {
List<SentMessages.SentMessage> sentMessages = new ArrayList<>();
if (message.rooms != null) {
for (String room : message.rooms) {
HttpRequest request = buildRoomRequest(room, message, proxy);
try {
HttpResponse response = httpClient.execute(request);
sentMessages.add(SentMessages.SentMessage.responded(room, SentMessages.SentMessage.TargetType.ROOM, message, request,
response));
} catch (Exception e) {
logger.error("failed to execute hipchat api http request", e);
sentMessages.add(SentMessages.SentMessage.error(room, SentMessages.SentMessage.TargetType.ROOM, message, e));
}
}
}
return new SentMessages(name, sentMessages);
}
public HttpRequest buildRoomRequest(String room, HipChatMessage message, HttpProxy proxy) {
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);
if (proxy != null) {
builder.proxy(proxy);
}
StringBuilder body = new StringBuilder();
body.append("room_id=").append(HttpRequest.encodeUrl(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("&notify=").append(message.notify ? "1" : "0");
}
builder.body(body.toString());
return builder.build();
}
static class Defaults {
@Nullable final String[] rooms;
@Nullable final String from;
@Nullable final Format format;
@Nullable final Color color;
@Nullable final Boolean notify;
Defaults(Settings settings) {
List<String> rooms = settings.getAsList(DEFAULT_ROOM_SETTING, null);
this.rooms = rooms == null ? null : rooms.toArray(Strings.EMPTY_ARRAY);
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);
}
}
}

View File

@ -1,63 +0,0 @@
/*
* 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.xpack.watcher.actions.hipchat;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatAccount;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatService;
import org.junit.Before;
import java.util.HashSet;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.hipchatAction;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class HipChatActionFactoryTests extends ESTestCase {
private HipChatActionFactory factory;
private HipChatService hipchatService;
@Before
public void init() throws Exception {
hipchatService = mock(HipChatService.class);
factory = new HipChatActionFactory(mock(TextTemplateEngine.class), hipchatService);
}
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 = createParser(jsonBuilder);
parser.nextToken();
ExecutableHipChatAction parsedAction = factory.parseExecutable("_w1", "_a1", parser);
assertThat(parsedAction.action(), is(action));
verify(account, times(1)).validateParsedTemplate("_w1", "_a1", action.message);
}
public void testParseActionUnknownAccount() throws Exception {
hipchatService = new HipChatService(Settings.EMPTY, null, new ClusterSettings(Settings.EMPTY,
new HashSet<>(HipChatService.getSettings())));
factory = new HipChatActionFactory(mock(TextTemplateEngine.class), hipchatService);
HipChatAction action = hipchatAction("_unknown", "_body").build();
XContentBuilder jsonBuilder = jsonBuilder().value(action);
XContentParser parser = createParser(jsonBuilder);
parser.nextToken();
expectThrows(IllegalArgumentException.class, () -> factory.parseExecutable("_w1", "_a1", parser));
}
}

View File

@ -1,296 +0,0 @@
/*
* 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.xpack.watcher.actions.hipchat;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.JodaCompatibleZonedDateTime;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.watcher.actions.Action;
import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.core.watcher.execution.Wid;
import org.elasticsearch.xpack.core.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatAccount;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatMessage;
import org.elasticsearch.xpack.watcher.notification.hipchat.HipChatService;
import org.elasticsearch.xpack.watcher.notification.hipchat.SentMessages;
import org.junit.Before;
import java.io.IOException;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContextBuilder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance;
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);
}
public void testExecute() throws Exception {
final String accountName = "account1";
TextTemplateEngine templateEngine = mock(TextTemplateEngine.class);
TextTemplate body = new TextTemplate("_body");
HipChatMessage.Template.Builder messageBuilder = new HipChatMessage.Template.Builder(body);
HipChatMessage.Template messageTemplate = messageBuilder.build();
HipChatAction action = new HipChatAction(accountName, messageTemplate, null);
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();
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
JodaCompatibleZonedDateTime jodaJavaNow = new JodaCompatibleZonedDateTime(now.toInstant(), ZoneOffset.UTC);
Wid wid = new Wid(randomAlphaOfLength(5), now);
WatchExecutionContext ctx = mockExecutionContextBuilder(wid.watchId())
.wid(wid)
.payload(payload)
.time(wid.watchId(), now)
.metadata(metadata)
.buildMock();
Map<String, Object> triggerModel = new HashMap<>();
triggerModel.put("triggered_time", jodaJavaNow);
triggerModel.put("scheduled_time", jodaJavaNow);
Map<String, Object> ctxModel = new HashMap<>();
ctxModel.put("id", ctx.id().value());
ctxModel.put("watch_id", wid.watchId());
ctxModel.put("payload", data);
ctxModel.put("metadata", metadata);
ctxModel.put("execution_time", jodaJavaNow);
ctxModel.put("trigger", triggerModel);
ctxModel.put("vars", Collections.emptyMap());
Map<String, Object> expectedModel = singletonMap("ctx", ctxModel);
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);
boolean responseFailure = randomBoolean();
HttpResponse response = new HttpResponse(responseFailure ? 404 : 200);
HttpRequest request = HttpRequest.builder("localhost", 12345).path("/").build();
SentMessages sentMessages = new SentMessages(accountName, Arrays.asList(
SentMessages.SentMessage.responded("_r1", SentMessages.SentMessage.TargetType.ROOM, message, request, response)
));
when(account.send(message, null)).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));
if (responseFailure) {
assertThat(result.status(), equalTo(Action.Result.Status.FAILURE));
} else {
assertThat(result.status(), equalTo(Action.Result.Status.SUCCESS));
}
assertThat(((HipChatAction.Result.Executed) result).sentMessages(), sameInstance(sentMessages));
assertValidToXContent(result);
}
public void testParser() throws Exception {
XContentBuilder builder = jsonBuilder().startObject();
String accountName = randomAlphaOfLength(10);
builder.field("account", accountName);
builder.startObject("message");
TextTemplate body = new TextTemplate("_body");
builder.field("body", body);
TextTemplate[] rooms = null;
if (randomBoolean()) {
TextTemplate r1 = new TextTemplate("_r1");
TextTemplate r2 = new TextTemplate("_r2");
rooms = new TextTemplate[] { r1, r2 };
builder.array("room", r1, r2);
}
TextTemplate[] users = null;
if (randomBoolean()) {
TextTemplate u1 = new TextTemplate("_u1");
TextTemplate u2 = new TextTemplate("_u2");
users = new TextTemplate[] { u1, u2 };
builder.array("user", u1, u2);
}
String from = null;
if (randomBoolean()) {
from = randomAlphaOfLength(10);
builder.field("from", from);
}
HipChatMessage.Format format = null;
if (randomBoolean()) {
format = randomFrom(HipChatMessage.Format.values());
builder.field("format", format.value());
}
TextTemplate color = null;
if (randomBoolean()) {
color = new TextTemplate(randomFrom(HipChatMessage.Color.values()).value());
builder.field("color", color);
}
Boolean notify = null;
if (randomBoolean()) {
notify = randomBoolean();
builder.field("notify", notify);
}
builder.endObject();
HttpProxy proxy = null;
if (randomBoolean()) {
proxy = new HttpProxy("localhost", 8080);
builder.startObject("proxy").field("host", "localhost").field("port", 8080).endObject();
}
builder.endObject();
BytesReference bytes = BytesReference.bytes(builder);
logger.info("hipchat action json [{}]", bytes.utf8ToString());
XContentParser parser = createParser(JsonXContent.jsonXContent, bytes);
parser.nextToken();
HipChatAction action = HipChatAction.parse("_watch", "_action", parser);
assertThat(action, notNullValue());
assertThat(action.account, is(accountName));
assertThat(action.proxy, is(proxy));
assertThat(action.message, notNullValue());
assertThat(action.message, is(new HipChatMessage.Template(body, rooms, users, from, format, color, notify)));
}
public void testParserSelfGenerated() throws Exception {
String accountName = randomAlphaOfLength(10);
TextTemplate body = new TextTemplate("_body");
HipChatMessage.Template.Builder templateBuilder = new HipChatMessage.Template.Builder(body);
XContentBuilder builder = jsonBuilder().startObject();
builder.field("account", accountName);
HttpProxy proxy = null;
if (randomBoolean()) {
proxy = new HttpProxy("localhost", 8080);
builder.startObject("proxy").field("host", "localhost").field("port", 8080).endObject();
}
builder.startObject("message");
builder.field("body", body);
if (randomBoolean()) {
TextTemplate r1 = new TextTemplate("_r1");
TextTemplate r2 = new TextTemplate("_r2");
templateBuilder.addRooms(r1, r2);
builder.array("room", r1, r2);
}
if (randomBoolean()) {
TextTemplate u1 = new TextTemplate("_u1");
TextTemplate u2 = new TextTemplate("_u2");
templateBuilder.addUsers(u1, u2);
builder.array("user", u1, u2);
}
if (randomBoolean()) {
String from = randomAlphaOfLength(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()) {
TextTemplate color = new TextTemplate(randomFrom(HipChatMessage.Color.values()).value());
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, proxy);
XContentBuilder jsonBuilder = jsonBuilder();
action.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
BytesReference bytes = BytesReference.bytes(builder);
logger.info("{}", bytes.utf8ToString());
XContentParser parser = createParser(JsonXContent.jsonXContent, bytes);
parser.nextToken();
HipChatAction parsedAction = HipChatAction.parse("_watch", "_action", parser);
assertThat(parsedAction, notNullValue());
assertThat(parsedAction, is(action));
}
public void testParserInvalid() throws Exception {
XContentBuilder builder = jsonBuilder().startObject().field("unknown_field", "value").endObject();
XContentParser parser = createParser(builder);
parser.nextToken();
try {
HipChatAction.parse("_watch", "_action", parser);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), is("failed to parse [hipchat] action [_watch/_action]. unexpected token [VALUE_STRING]"));
}
}
// ensure that toXContent can be serialized and read again
private void assertValidToXContent(Action.Result result) throws IOException {
try (XContentBuilder builder = jsonBuilder()) {
builder.startObject();
result.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
Strings.toString(builder);
try (XContentParser parser = XContentType.JSON.xContent()
.createParser(NamedXContentRegistry.EMPTY, LoggingDeprecationHandler.INSTANCE, Strings.toString(builder))) {
parser.map();
}
}
}
}

View File

@ -1,63 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import java.util.HashSet;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class HipChatAccountsTests extends ESTestCase {
private HttpClient httpClient;
@Before
public void init() throws Exception {
httpClient = mock(HttpClient.class);
}
public void testProxy() throws Exception {
Settings.Builder builder = Settings.builder()
.put("xpack.notification.hipchat.default_account", "account1");
addAccountSettings("account1", builder);
HipChatService service = new HipChatService(builder.build(), httpClient, new ClusterSettings(Settings.EMPTY,
new HashSet<>(HipChatService.getSettings())));
HipChatAccount account = service.getAccount("account1");
HipChatMessage hipChatMessage = new HipChatMessage("body", new String[]{"rooms"}, null, "from", null, null, null);
ArgumentCaptor<HttpRequest> argumentCaptor = ArgumentCaptor.forClass(HttpRequest.class);
when(httpClient.execute(argumentCaptor.capture())).thenReturn(new HttpResponse(200));
HttpProxy proxy = new HttpProxy("localhost", 8080);
account.send(hipChatMessage, proxy);
HttpRequest request = argumentCaptor.getValue();
assertThat(request.proxy(), is(proxy));
}
private void addAccountSettings(String name, Settings.Builder builder) {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.notification.hipchat.account." + name + ".secure_auth_token", randomAlphaOfLength(50));
HipChatAccount.Profile profile = randomFrom(HipChatAccount.Profile.values());
builder.put("xpack.notification.hipchat.account." + name + ".profile", profile.value());
builder.setSecureSettings(secureSettings);
if (profile == HipChatAccount.Profile.INTEGRATION) {
builder.put("xpack.notification.hipchat.account." + name + ".room", randomAlphaOfLength(10));
}
}
}

View File

@ -1,325 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
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.xpack.core.watcher.support.xcontent.WatcherParams;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
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.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
public class HipChatMessageTests extends ESTestCase {
public void testToXContent() throws Exception {
String message = randomAlphaOfLength(10);
String[] rooms = generateRandomStringArray(3, 10, true);
String[] users = generateRandomStringArray(3, 10, true);
String from = randomBoolean() ? null : randomAlphaOfLength(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 = BytesReference.bytes(builder);
XContentParser parser = createParser(JsonXContent.jsonXContent, 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 = parser.list().stream().map(Object::toString).toArray(String[]::new);
} else if ("user".equals(currentFieldName)) {
users = parser.list().stream().map(Object::toString).toArray(String[]::new);
} 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 xcontent 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));
}
public void testEquals() throws Exception {
String message = randomAlphaOfLength(10);
String[] rooms = generateRandomStringArray(3, 10, true);
String[] users = generateRandomStringArray(3, 10, true);
String from = randomBoolean() ? null : randomAlphaOfLength(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 :
randomFromWithExcludes(HipChatMessage.Format.values(), format);
}
if (rarely()) {
equals = false;
color = color == null ?
randomFrom(HipChatMessage.Color.values()) :
randomBoolean() ?
null :
randomFromWithExcludes(HipChatMessage.Color.values(), color);
}
if (rarely()) {
equals = false;
notify = notify == null ? (Boolean) randomBoolean() : randomBoolean() ? null : !notify;
}
}
HipChatMessage msg2 = new HipChatMessage(message, rooms, users, from, format, color, notify);
assertThat(msg1.equals(msg2), is(equals));
}
public void testTemplateParse() throws Exception {
XContentBuilder jsonBuilder = jsonBuilder();
jsonBuilder.startObject();
TextTemplate body = new TextTemplate(randomAlphaOfLength(200));
jsonBuilder.field("body", body, ToXContent.EMPTY_PARAMS);
TextTemplate[] rooms = null;
if (randomBoolean()) {
jsonBuilder.startArray("room");
rooms = new TextTemplate[randomIntBetween(1, 3)];
for (int i = 0; i < rooms.length; i++) {
rooms[i] = new TextTemplate(randomAlphaOfLength(10));
rooms[i].toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
}
jsonBuilder.endArray();
}
TextTemplate[] users = null;
if (randomBoolean()) {
jsonBuilder.startArray("user");
users = new TextTemplate[randomIntBetween(1, 3)];
for (int i = 0; i < users.length; i++) {
users[i] = new TextTemplate(randomAlphaOfLength(10));
users[i].toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
}
jsonBuilder.endArray();
}
String from = null;
if (randomBoolean()) {
from = randomAlphaOfLength(10);
jsonBuilder.field("from", from);
}
TextTemplate color = null;
if (randomBoolean()) {
color = new TextTemplate(randomAlphaOfLength(10));
jsonBuilder.field("color", color, ToXContent.EMPTY_PARAMS);
}
HipChatMessage.Format format = null;
if (randomBoolean()) {
format = randomFrom(HipChatMessage.Format.values());
jsonBuilder.field("format", format.value());
}
Boolean notify = null;
if (randomBoolean()) {
notify = randomBoolean();
jsonBuilder.field("notify", notify);
}
BytesReference bytes = BytesReference.bytes(jsonBuilder.endObject());
XContentParser parser = createParser(JsonXContent.jsonXContent, 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));
}
public void testTemplateParseSelfGenerated() throws Exception {
TextTemplate body = new TextTemplate(randomAlphaOfLength(10));
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(new TextTemplate(randomAlphaOfLength(10)));
}
}
if (randomBoolean()) {
int count = randomIntBetween(1, 3);
for (int i = 0; i < count; i++) {
templateBuilder.addUsers(new TextTemplate(randomAlphaOfLength(10)));
}
}
if (randomBoolean()) {
templateBuilder.setFrom(randomAlphaOfLength(10));
}
if (randomBoolean()) {
templateBuilder.setColor(new TextTemplate(randomAlphaOfLength(5)));
}
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 = BytesReference.bytes(jsonBuilder);
XContentParser parser = createParser(JsonXContent.jsonXContent, bytes);
parser.nextToken();
HipChatMessage.Template parsed = HipChatMessage.Template.parse(parser);
assertThat(parsed, equalTo(template));
}
public void testAuthTokenParamIsFiltered() throws Exception {
HttpResponse response = new HttpResponse(500);
String token = randomAlphaOfLength(20);
HttpRequest request = HttpRequest.builder("localhost", 1234).setParam("auth_token", token).build();
// String body, String[] rooms, String[] users, String from, Format format, Color color, Boolean notify
HipChatMessage hipChatMessage = new HipChatMessage("body", new String[]{"room"}, null, "from",
HipChatMessage.Format.TEXT, HipChatMessage.Color.RED, false);
SentMessages.SentMessage sentMessage = SentMessages.SentMessage.responded("targetName", SentMessages.SentMessage.TargetType.ROOM,
hipChatMessage, request, response);
try (XContentBuilder builder = jsonBuilder()) {
WatcherParams params = WatcherParams.builder().hideSecrets(false).build();
sentMessage.toXContent(builder, params);
assertThat(Strings.toString(builder), containsString(token));
try (XContentParser parser = builder.contentType().xContent()
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
Strings.toString(builder))) {
parser.map();
}
}
try (XContentBuilder builder = jsonBuilder()) {
sentMessage.toXContent(builder, ToXContent.EMPTY_PARAMS);
assertThat(Strings.toString(builder), not(containsString(token)));
try (XContentParser parser = builder.contentType().xContent()
.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
Strings.toString(builder))) {
parser.map();
}
}
}
static <E extends Enum> E randomFromWithExcludes(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);
}
}

View File

@ -1,279 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.junit.Before;
import java.util.HashSet;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.Mockito.mock;
public class HipChatServiceTests extends ESTestCase {
private HttpClient httpClient;
@Before
public void init() throws Exception {
httpClient = mock(HttpClient.class);
}
public void testSingleAccountV1() throws Exception {
String accountName = randomAlphaOfLength(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();
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.notification.hipchat.account." + accountName + ".secure_auth_token", "_token");
Settings.Builder settingsBuilder = Settings.builder()
.put("xpack.notification.hipchat.account." + accountName + ".profile", HipChatAccount.Profile.V1.value())
.setSecureSettings(secureSettings);
if (host != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".host", host);
}
if (port > 0) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".port", port);
}
buildMessageDefaults(accountName, settingsBuilder, defaultRoom, null, defaultFrom, defaultColor, defaultFormat, defaultNotify);
HipChatService service = new HipChatService(settingsBuilder.build(), httpClient,
new ClusterSettings(settingsBuilder.build(), new HashSet<>(HipChatService.getSettings())));
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.getAccount(null), sameInstance(account));
}
public void testSingleAccountIntegration() throws Exception {
String accountName = randomAlphaOfLength(10);
String host = randomBoolean() ? null : "_host";
int port = randomBoolean() ? -1 : randomIntBetween(300, 400);
String room = randomAlphaOfLength(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();
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.notification.hipchat.account." + accountName + ".secure_auth_token", "_token");
Settings.Builder settingsBuilder = Settings.builder()
.put("xpack.notification.hipchat.account." + accountName + ".profile",
HipChatAccount.Profile.INTEGRATION.value())
.setSecureSettings(secureSettings)
.put("xpack.notification.hipchat.account." + accountName + ".room", room);
if (host != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".host", host);
}
if (port > 0) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".port", port);
}
buildMessageDefaults(accountName, settingsBuilder, null, null, defaultFrom, defaultColor, defaultFormat, defaultNotify);
HipChatService service = new HipChatService(settingsBuilder.build(), httpClient,
new ClusterSettings(settingsBuilder.build(), new HashSet<>(HipChatService.getSettings())));
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.getAccount(null), sameInstance(account));
}
public void testSingleAccountIntegrationNoRoomSetting() throws Exception {
String accountName = randomAlphaOfLength(10);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.notification.hipchat.account." + accountName + ".secure_auth_token", "_token");
Settings.Builder settingsBuilder = Settings.builder()
.put("xpack.notification.hipchat.account." + accountName + ".profile",
HipChatAccount.Profile.INTEGRATION.value())
.setSecureSettings(secureSettings);
SettingsException e = expectThrows(SettingsException.class, () ->
new HipChatService(settingsBuilder.build(), httpClient,
new ClusterSettings(settingsBuilder.build(), new HashSet<>(HipChatService.getSettings()))).getAccount(null));
assertThat(e.getMessage(), containsString("missing required [room] setting for [integration] account profile"));
}
public void testSingleAccountUser() throws Exception {
String accountName = randomAlphaOfLength(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();
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString("xpack.notification.hipchat.account." + accountName + ".secure_auth_token", "_token");
Settings.Builder settingsBuilder = Settings.builder()
.put("xpack.notification.hipchat.account." + accountName + ".profile", HipChatAccount.Profile.USER.value())
.setSecureSettings(secureSettings);
if (host != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".host", host);
}
if (port > 0) {
settingsBuilder.put("xpack.notification.hipchat.account." + accountName + ".port", port);
}
buildMessageDefaults(accountName, settingsBuilder, defaultRoom, defaultUser, null, defaultColor, defaultFormat, defaultNotify);
HipChatService service = new HipChatService(settingsBuilder.build(), httpClient,
new ClusterSettings(settingsBuilder.build(), new HashSet<>(HipChatService.getSettings())));
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.getAccount(null), sameInstance(account));
}
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("xpack.notification.hipchat.default_account", defaultAccount);
final MockSecureSettings secureSettings = new MockSecureSettings();
settingsBuilder.setSecureSettings(secureSettings);
final boolean customGlobalServer = randomBoolean();
if (customGlobalServer) {
settingsBuilder.put("xpack.notification.hipchat.host", "_host_global");
settingsBuilder.put("xpack.notification.hipchat.port", 299);
}
for (int i = 0; i < 5; i++) {
String name = "_a" + i;
String prefix = "xpack.notification.hipchat.account." + name;
HipChatAccount.Profile profile = randomFrom(HipChatAccount.Profile.values());
settingsBuilder.put(prefix + ".profile", profile);
secureSettings.setString(prefix + ".secure_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);
}
HipChatService service = new HipChatService(settingsBuilder.build(), httpClient,
new ClusterSettings(settingsBuilder.build(), new HashSet<>(HipChatService.getSettings())));
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.getAccount(null), sameInstance(service.getAccount(defaultAccount)));
}
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("xpack.notification.hipchat.account." + account + ".message_defaults.room", room);
}
if (user != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + account + ".message_defaults.user", user);
}
if (from != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + account + ".message_defaults.from", from);
}
if (color != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + account + ".message_defaults.color", color.value());
}
if (format != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + account + ".message_defaults.format", format);
}
if (notify != null) {
settingsBuilder.put("xpack.notification.hipchat.account." + account + ".message_defaults.notify", notify);
}
}
}

View File

@ -1,181 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.MockSecureSettings;
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.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class IntegrationAccountTests extends ESTestCase {
public void testSettings() throws Exception {
String accountName = "_name";
Settings.Builder sb = Settings.builder();
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), authToken);
sb.setSecureSettings(secureSettings);
String host = HipChatServer.DEFAULT.host();
if (randomBoolean()) {
host = randomAlphaOfLength(10);
sb.put("host", host);
}
int port = HipChatServer.DEFAULT.port();
if (randomBoolean()) {
port = randomIntBetween(300, 400);
sb.put("port", port);
}
String room = randomAlphaOfLength(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(Logger.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));
}
public void testSettingsNoAuthToken() throws Exception {
Settings.Builder sb = Settings.builder();
sb.put(IntegrationAccount.ROOM_SETTING, randomAlphaOfLength(10));
try {
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(Logger.class));
fail("Expected SettingsException");
} catch (SettingsException e) {
assertThat(e.getMessage(), is("hipchat account [_name] missing required [secure_auth_token] secure setting"));
}
}
public void testSettingsWithoutRoom() throws Exception {
Settings.Builder sb = Settings.builder();
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), authToken);
sb.setSecureSettings(secureSettings);
try {
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(Logger.class));
fail("Expected SettingsException");
} catch (SettingsException e) {
assertThat(e.getMessage(), containsString("missing required [room] setting for [integration] account profile"));
}
}
public void testSettingsWithoutMultipleRooms() throws Exception {
Settings.Builder sb = Settings.builder();
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), authToken);
sb.setSecureSettings(secureSettings);
sb.put(IntegrationAccount.ROOM_SETTING, "_r1,_r2");
try {
new IntegrationAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(Logger.class));
fail("Expected SettingsException");
} catch (SettingsException e) {
assertThat(e.getMessage(), containsString("[room] setting for [integration] account must only be set with a single value"));
}
}
public void testSend() throws Exception {
String token = randomAlphaOfLength(10);
HttpClient httpClient = mock(HttpClient.class);
String room = "Room with Spaces";
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), token);
IntegrationAccount account = new IntegrationAccount("_name", Settings.builder()
.put("host", "_host")
.put("port", "443")
.setSecureSettings(secureSettings)
.put("room", room)
.build(), HipChatServer.DEFAULT, httpClient, mock(Logger.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)
// url encoded already
.path("/v2/room/Room+with+Spaces/notification")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Bearer " + token)
.body(Strings.toString((builder, params) -> {
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);
SentMessages sentMessages = account.send(message, null);
verify(httpClient).execute(req);
assertThat(sentMessages.asList(), hasSize(1));
try (XContentBuilder builder = jsonBuilder()) {
sentMessages.asList().get(0).toXContent(builder, ToXContent.EMPTY_PARAMS);
assertThat(Strings.toString(builder), not(containsString(token)));
}
}
}

View File

@ -1,313 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpProxy;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import org.elasticsearch.xpack.watcher.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
import org.mockito.ArgumentCaptor;
import java.util.HashMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class UserAccountTests extends ESTestCase {
public void testSettings() throws Exception {
String accountName = "_name";
Settings.Builder sb = Settings.builder();
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(UserAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), authToken);
sb.setSecureSettings(secureSettings);
String host = HipChatServer.DEFAULT.host();
if (randomBoolean()) {
host = randomAlphaOfLength(10);
sb.put("host", host);
}
int port = HipChatServer.DEFAULT.port();
if (randomBoolean()) {
port = randomIntBetween(300, 400);
sb.put("port", 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(Logger.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));
}
public void testSettingsNoAuthToken() throws Exception {
Settings.Builder sb = Settings.builder();
try {
new UserAccount("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(Logger.class));
fail("Expected SettingsException");
} catch (SettingsException e) {
assertThat(e.getMessage(), is("hipchat account [_name] missing required [secure_auth_token] secure setting"));
}
}
public void testSend() throws Exception {
HttpClient httpClient = mock(HttpClient.class);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), "_token");
UserAccount account = new UserAccount("_name", Settings.builder()
.put("host", "_host")
.put("port", "443")
.setSecureSettings(secureSettings)
.build(), HipChatServer.DEFAULT, httpClient, mock(Logger.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(Strings.toString((builder, params) -> {
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): {}", BytesReference.bytes(jsonBuilder().value(reqR1)).utf8ToString());
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(Strings.toString((builder, params) -> {
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): {}", BytesReference.bytes(jsonBuilder().value(reqR1)).utf8ToString());
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(Strings.toString((builder, params) -> {
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): {}", BytesReference.bytes(jsonBuilder().value(reqU1)).utf8ToString());
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(Strings.toString((builder, params) -> {
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): {}", BytesReference.bytes(jsonBuilder().value(reqU2)).utf8ToString());
HttpResponse resU2 = mock(HttpResponse.class);
when(resU2.status()).thenReturn(200);
when(httpClient.execute(reqU2)).thenReturn(resU2);
account.send(message, null);
verify(httpClient).execute(reqR1);
verify(httpClient).execute(reqR2);
verify(httpClient).execute(reqU2);
verify(httpClient).execute(reqU2);
}
public void testColorIsOptional() throws Exception {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), "awesome-auth-token");
Settings settings = Settings.builder()
.put("user", "testuser")
.setSecureSettings(secureSettings)
.build();
UserAccount userAccount = createUserAccount(settings);
TextTemplate body = new TextTemplate("body");
TextTemplate[] rooms = new TextTemplate[] { new TextTemplate("room")};
HipChatMessage.Template template =
new HipChatMessage.Template(body, rooms, null, "sender", HipChatMessage.Format.TEXT, null, true);
HipChatMessage message = userAccount.render("watchId", "actionId", new MockTextTemplateEngine(), template, new HashMap<>());
assertThat(message.color, is(nullValue()));
}
public void testFormatIsOptional() throws Exception {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), "awesome-auth-token");
Settings settings = Settings.builder()
.put("user", "testuser")
.setSecureSettings(secureSettings)
.build();
UserAccount userAccount = createUserAccount(settings);
TextTemplate body = new TextTemplate("body");
TextTemplate[] rooms = new TextTemplate[] { new TextTemplate("room") };
HipChatMessage.Template template = new HipChatMessage.Template(body, rooms, null, "sender", null,
new TextTemplate("yellow"), true);
HipChatMessage message = userAccount.render("watchId", "actionId", new MockTextTemplateEngine(), template, new HashMap<>());
assertThat(message.format, is(nullValue()));
}
public void testRoomNameIsUrlEncoded() throws Exception {
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), "awesome-auth-token");
Settings settings = Settings.builder()
.put("user", "testuser")
.setSecureSettings(secureSettings)
.build();
HipChatServer hipChatServer = mock(HipChatServer.class);
HttpClient httpClient = mock(HttpClient.class);
UserAccount account = new UserAccount("notify-monitoring", settings, hipChatServer, httpClient, logger);
TextTemplate[] rooms = new TextTemplate[] { new TextTemplate("Room with Spaces")};
HipChatMessage.Template template =
new HipChatMessage.Template(new TextTemplate("body"), rooms, null, "sender", HipChatMessage.Format.TEXT, null, true);
HipChatMessage message = account.render("watchId", "actionId", new MockTextTemplateEngine(), template, new HashMap<>());
account.send(message, HttpProxy.NO_PROXY);
ArgumentCaptor<HttpRequest> captor = ArgumentCaptor.forClass(HttpRequest.class);
verify(httpClient).execute(captor.capture());
assertThat(captor.getAllValues(), hasSize(1));
assertThat(captor.getValue().path(), not(containsString("Room with Spaces")));
assertThat(captor.getValue().path(), containsString("Room%20with%20Spaces"));
}
private UserAccount createUserAccount(Settings settings) {
HipChatServer hipChatServer = mock(HipChatServer.class);
HttpClient httpClient = mock(HttpClient.class);
return new UserAccount("notify-monitoring", settings, hipChatServer, httpClient, logger);
}
}

View File

@ -1,174 +0,0 @@
/*
* 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.xpack.watcher.notification.hipchat;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.common.http.HttpClient;
import org.elasticsearch.xpack.watcher.common.http.HttpMethod;
import org.elasticsearch.xpack.watcher.common.http.HttpRequest;
import org.elasticsearch.xpack.watcher.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.common.http.Scheme;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class V1AccountTests extends ESTestCase {
public void testSettings() throws Exception {
String accountName = "_name";
Settings.Builder sb = Settings.builder();
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(V1Account.SECURE_AUTH_TOKEN_SETTING.getKey(), authToken);
sb.setSecureSettings(secureSettings);
String host = HipChatServer.DEFAULT.host();
if (randomBoolean()) {
host = randomAlphaOfLength(10);
sb.put("host", host);
}
int port = HipChatServer.DEFAULT.port();
if (randomBoolean()) {
port = randomIntBetween(300, 400);
sb.put("port", 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 = randomAlphaOfLength(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(Logger.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));
}
public void testSettingsNoAuthToken() throws Exception {
Settings.Builder sb = Settings.builder();
try {
new V1Account("_name", sb.build(), HipChatServer.DEFAULT, mock(HttpClient.class), mock(Logger.class));
fail("Expected SettingsException");
} catch (SettingsException e) {
assertThat(e.getMessage(), is("hipchat account [_name] missing required [secure_auth_token] secure setting"));
}
}
public void testSend() throws Exception {
HttpClient httpClient = mock(HttpClient.class);
String authToken = randomAlphaOfLength(50);
final MockSecureSettings secureSettings = new MockSecureSettings();
secureSettings.setString(IntegrationAccount.SECURE_AUTH_TOKEN_SETTING.getKey(), "_token");
V1Account account = new V1Account("_name", Settings.builder()
.put("host", "_host")
.put("port", "443")
.setSecureSettings(secureSettings)
.build(), HipChatServer.DEFAULT, httpClient, mock(Logger.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[] { "Room with Spaces", "_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("Room+with+Spaces&")
.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): {}", BytesReference.bytes(jsonBuilder().value(req1)).utf8ToString());
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): {}", BytesReference.bytes(jsonBuilder().value(req2)).utf8ToString());
HttpResponse res2 = mock(HttpResponse.class);
when(res2.status()).thenReturn(200);
when(httpClient.execute(req2)).thenReturn(res2);
account.send(message, null);
verify(httpClient).execute(req1);
verify(httpClient).execute(req2);
}
}

View File

@ -1,31 +0,0 @@
apply plugin: 'elasticsearch.standalone-rest-test'
apply plugin: 'elasticsearch.rest-test'
dependencies {
testCompile "org.elasticsearch.plugin:x-pack-core:${version}"
testCompile project(path: xpackModule('watcher'), configuration: 'runtime')
}
String integrationAccount = System.getenv('hipchat_auth_token_integration')
String userAccount = System.getenv('hipchat_auth_token_user')
String v1Account = System.getenv('hipchat_auth_token_v1')
integTestCluster {
setting 'xpack.security.enabled', 'false'
setting 'xpack.monitoring.enabled', 'false'
setting 'xpack.ml.enabled', 'false'
setting 'xpack.license.self_generated.type', 'trial'
setting 'logger.org.elasticsearch.xpack.watcher', 'DEBUG'
setting 'xpack.notification.hipchat.account.integration_account.profile', 'integration'
setting 'xpack.notification.hipchat.account.integration_account.room', 'test-watcher'
setting 'xpack.notification.hipchat.account.user_account.profile', 'user'
setting 'xpack.notification.hipchat.account.v1_account.profile', 'v1'
keystoreSetting 'xpack.notification.hipchat.account.integration_account.secure_auth_token', integrationAccount
keystoreSetting 'xpack.notification.hipchat.account.user_account.secure_auth_token', userAccount
keystoreSetting 'xpack.notification.hipchat.account.v1_account.secure_auth_token', v1Account
}
if (!integrationAccount && !userAccount && !v1Account) {
integTest.enabled = false
testingConventions.enabled = false
}

View File

@ -1,75 +0,0 @@
/*
* 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.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ClientYamlTestResponse;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import org.elasticsearch.xpack.core.watcher.support.WatcherIndexTemplateRegistryField;
import org.junit.After;
import org.junit.Before;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.is;
/** Runs rest tests against external cluster */
public class WatcherHipchatYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public WatcherHipchatYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws Exception {
return ESClientYamlSuiteTestCase.createParameters();
}
@Before
public void startWatcher() throws Exception {
final List<String> watcherTemplates = Arrays.asList(WatcherIndexTemplateRegistryField.TEMPLATE_NAMES);
assertBusy(() -> {
try {
getAdminExecutionContext().callApi("watcher.start", emptyMap(), emptyList(), emptyMap());
for (String template : watcherTemplates) {
ClientYamlTestResponse templateExistsResponse = getAdminExecutionContext().callApi("indices.exists_template",
singletonMap("name", template), emptyList(), emptyMap());
assertThat(templateExistsResponse.getStatusCode(), is(200));
}
ClientYamlTestResponse response =
getAdminExecutionContext().callApi("watcher.stats", emptyMap(), emptyList(), emptyMap());
String state = (String) response.evaluate("stats.0.watcher_state");
assertThat(state, is("started"));
} catch (IOException e) {
throw new AssertionError(e);
}
});
}
@After
public void stopWatcher() throws Exception {
assertBusy(() -> {
try {
getAdminExecutionContext().callApi("watcher.stop", emptyMap(), emptyList(), emptyMap());
ClientYamlTestResponse response =
getAdminExecutionContext().callApi("watcher.stats", emptyMap(), emptyList(), emptyMap());
String state = (String) response.evaluate("stats.0.watcher_state");
assertThat(state, is("stopped"));
} catch (IOException e) {
throw new AssertionError(e);
}
});
}
}

View File

@ -1,279 +0,0 @@
---
"Test Hipchat v1 account Action":
- do:
cluster.health:
wait_for_status: yellow
- do:
watcher.put_watch:
id: "hipchat_v1_watch"
body: >
{
"trigger": {
"schedule": {
"interval": "1d"
}
},
"input": {
"simple": {
"foo": "something from input"
}
},
"actions": {
"my_hipchat_action": {
"hipchat": {
"account": "v1_account",
"message": {
"from" : "watcher-tests",
"room" : ["test-watcher", "test-watcher-2", "test watcher with spaces"],
"body": "From input {{ctx.payload.foo}}, and some tests (facepalm) in the v1 account",
"format": "text",
"color": "red",
"notify": true
}
}
}
}
}
- do:
watcher.execute_watch:
id: "hipchat_v1_watch"
body: >
{
"record_execution": true
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.actions.0.id: "my_hipchat_action" }
- match: { watch_record.result.actions.0.type: "hipchat" }
- match: { watch_record.result.actions.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.account: "v1_account" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.1.room: "test-watcher-2" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.2.room: "test watcher with spaces" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.1.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.2.status: "success" }
# Waits for the watcher history index to be available
- do:
cluster.health:
index: ".watcher-history-*"
wait_for_no_relocating_shards: true
timeout: 60s
- do:
indices.refresh: {}
- do:
search:
rest_total_hits_as_int: true
index: ".watcher-history-*"
body: >
{
"query" : {
"term" : {
"watch_id" : "hipchat_v1_watch"
}
}
}
- match: { hits.total: 1 }
- match: { hits.hits.0._source.state: "executed" }
- match: { hits.hits.0._source.result.actions.0.id: "my_hipchat_action" }
- match: { hits.hits.0._source.result.actions.0.type: "hipchat" }
- match: { hits.hits.0._source.result.actions.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.account: "v1_account" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.1.room: "test-watcher-2" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.2.room: "test watcher with spaces" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.1.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.2.status: "success" }
---
"Test Hipchat integration account Action":
- do:
cluster.health:
wait_for_status: yellow
# custom rooms, custom users and custom from are not allowed for this account type to be configured
- do:
watcher.put_watch:
id: "hipchat_integration_account_watch"
body: >
{
"trigger": {
"schedule": {
"interval": "1d"
}
},
"input": {
"simple": {
"foo": "something from input"
}
},
"actions": {
"my_hipchat_action": {
"hipchat": {
"account": "integration_account",
"message": {
"body": "From input {{ctx.payload.foo}}, and some tests (facepalm) in the integration account",
"format": "text",
"color": "red",
"notify": true
}
}
}
}
}
- do:
watcher.execute_watch:
id: "hipchat_integration_account_watch"
body: >
{
"record_execution": true
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.actions.0.id: "my_hipchat_action" }
- match: { watch_record.result.actions.0.type: "hipchat" }
- match: { watch_record.result.actions.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.account: "integration_account" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
# Waits for the watcher history index to be available
- do:
cluster.health:
index: ".watcher-history-*"
wait_for_no_relocating_shards: true
timeout: 60s
- do:
indices.refresh: {}
- do:
search:
rest_total_hits_as_int: true
index: ".watcher-history-*"
body: >
{
"query" : {
"term" : {
"watch_id" : "hipchat_integration_account_watch"
}
}
}
- match: { hits.total: 1 }
- match: { hits.hits.0._source.state: "executed" }
- match: { hits.hits.0._source.result.actions.0.id: "my_hipchat_action" }
- match: { hits.hits.0._source.result.actions.0.type: "hipchat" }
- match: { hits.hits.0._source.result.actions.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.account: "integration_account" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.status: "success" }
---
"Test Hipchat user account Action":
- do:
cluster.health:
wait_for_status: yellow
- do:
watcher.put_watch:
id: "hipchat_user_account_watch"
body: >
{
"trigger": {
"schedule": {
"interval": "1d"
}
},
"input": {
"simple": {
"foo": "something from input"
}
},
"actions": {
"my_hipchat_action": {
"hipchat": {
"account": "user_account",
"message": {
"user" : [ "watcher@elastic.co" ],
"room" : ["test-watcher", "test-watcher-2", "test watcher with spaces"],
"body": "From input {{ctx.payload.foo}}, and some tests (facepalm) in the user_account test. <b>bold</b>",
"format": "html"
}
}
}
}
}
- do:
watcher.execute_watch:
id: "hipchat_user_account_watch"
body: >
{
"record_execution": true
}
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.actions.0.id: "my_hipchat_action" }
- match: { watch_record.result.actions.0.type: "hipchat" }
- match: { watch_record.result.actions.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.account: "user_account" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.1.room: "test-watcher-2" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.2.room: "test watcher with spaces" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.3.user: "watcher@elastic.co" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.0.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.1.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.2.status: "success" }
- match: { watch_record.result.actions.0.hipchat.sent_messages.3.status: "success" }
# Waits for the watcher history index to be available
- do:
cluster.health:
index: ".watcher-history-*"
wait_for_no_relocating_shards: true
timeout: 60s
- do:
indices.refresh: {}
- do:
search:
rest_total_hits_as_int: true
index: ".watcher-history-*"
body: >
{
"query" : {
"term" : {
"watch_id" : "hipchat_user_account_watch"
}
}
}
- match: { hits.total: 1 }
- match: { hits.hits.0._source.state: "executed" }
- match: { hits.hits.0._source.result.actions.0.id: "my_hipchat_action" }
- match: { hits.hits.0._source.result.actions.0.type: "hipchat" }
- match: { hits.hits.0._source.result.actions.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.account: "user_account" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.room: "test-watcher" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.1.room: "test-watcher-2" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.2.room: "test watcher with spaces" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.3.user: "watcher@elastic.co" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.1.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.2.status: "success" }
- match: { hits.hits.0._source.result.actions.0.hipchat.sent_messages.1.status: "success" }