Add mappings for Jira action (elastic/elasticsearch#4155)

This commit updates the watch_history.json file so that it includes mappings for the new Jira action. It also update the JiraIssue format so that it now includes the name of the account used to create the Jira issue. It also update the REST tests to check that Jira action result are searchable and hide the user's password.

Original commit: elastic/x-pack-elasticsearch@75888f7748
This commit is contained in:
Tanguy Leroux 2016-11-23 11:53:06 +01:00 committed by GitHub
parent 5d042fc1b8
commit a32f2096a6
5 changed files with 308 additions and 26 deletions

View File

@ -90,7 +90,7 @@ public class JiraAccount {
.build();
HttpResponse response = httpClient.execute(request);
return JiraIssue.responded(fields, request, response);
return JiraIssue.responded(name, fields, request, response);
}
private static SettingsException requiredSettingException(String account, String setting) {

View File

@ -17,6 +17,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.xpack.common.http.HttpRequest;
import org.elasticsearch.xpack.common.http.HttpResponse;
import org.elasticsearch.xpack.watcher.actions.jira.JiraAction;
import org.elasticsearch.xpack.watcher.support.xcontent.WatcherParams;
import java.io.IOException;
import java.util.ArrayList;
@ -26,16 +27,18 @@ import java.util.Objects;
public class JiraIssue implements ToXContent {
@Nullable final String account;
private final Map<String, Object> fields;
@Nullable private final HttpRequest request;
@Nullable private final HttpResponse response;
@Nullable private final String failureReason;
public static JiraIssue responded(Map<String, Object> fields, HttpRequest request, HttpResponse response) {
return new JiraIssue(fields, request, response, resolveFailureReason(response));
public static JiraIssue responded(String account, Map<String, Object> fields, HttpRequest request, HttpResponse response) {
return new JiraIssue(account, fields, request, response, resolveFailureReason(response));
}
JiraIssue(Map<String, Object> fields, HttpRequest request, HttpResponse response, String failureReason) {
JiraIssue(String account, Map<String, Object> fields, HttpRequest request, HttpResponse response, String failureReason) {
this.account = account;
this.fields = fields;
this.request = request;
this.response = response;
@ -46,6 +49,10 @@ public class JiraIssue implements ToXContent {
return failureReason == null;
}
public String getAccount() {
return account;
}
public HttpRequest getRequest() {
return request;
}
@ -67,28 +74,30 @@ public class JiraIssue implements ToXContent {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
JiraIssue sentEvent = (JiraIssue) o;
return Objects.equals(fields, sentEvent.fields) &&
Objects.equals(request, sentEvent.request) &&
Objects.equals(response, sentEvent.response) &&
Objects.equals(failureReason, sentEvent.failureReason);
JiraIssue issue = (JiraIssue) o;
return Objects.equals(account, issue.account) &&
Objects.equals(fields, issue.fields) &&
Objects.equals(request, issue.request) &&
Objects.equals(response, issue.response) &&
Objects.equals(failureReason, issue.failureReason);
}
@Override
public int hashCode() {
return Objects.hash(fields, request, response, failureReason);
return Objects.hash(account, fields, request, response, failureReason);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(Field.ACCOUNT.getPreferredName(), account);
if (fields != null) {
builder.field(Field.FIELDS.getPreferredName(), fields);
}
if (successful() == false) {
builder.field(Field.REASON.getPreferredName(), failureReason);
if (request != null) {
builder.field(Field.REQUEST.getPreferredName(), request, params);
builder.field(Field.REQUEST.getPreferredName(), request, WatcherParams.builder().hideSecrets(true).build());
}
if (response != null) {
builder.field(Field.RESPONSE.getPreferredName(), response, params);
@ -181,6 +190,7 @@ public class JiraIssue implements ToXContent {
private interface Field {
ParseField FIELDS = JiraAction.Field.FIELDS;
ParseField ACCOUNT = new ParseField("account");
ParseField REASON = new ParseField("reason");
ParseField REQUEST = new ParseField("request");
ParseField RESPONSE = new ParseField("response");

View File

@ -28,6 +28,15 @@
"enabled": false
}
}
},
{
"disabled_jira_custom_fields": {
"path_match": "result.actions.jira.fields.customfield_*",
"mapping": {
"type": "object",
"enabled": false
}
}
}
],
"dynamic": false,
@ -358,6 +367,80 @@
}
}
},
"jira" : {
"type": "object",
"dynamic": true,
"properties": {
"account": {
"type": "keyword"
},
"reason": {
"type": "text"
},
"request" : {
"type" : "object",
"enabled" : false
},
"response" : {
"type" : "object",
"enabled" : false
},
"fields": {
"type": "object",
"dynamic": true,
"properties": {
"summary": {
"type": "text"
},
"description": {
"type": "text"
},
"labels" : {
"type": "text"
},
"project" : {
"type" : "object",
"dynamic" : true,
"properties" : {
"key" : {
"type" : "keyword"
},
"id" : {
"type" : "keyword"
}
}
},
"issuetype" : {
"type" : "object",
"dynamic" : true,
"properties" : {
"name" : {
"type": "keyword"
},
"id" : {
"type" : "keyword"
}
}
}
}
},
"result": {
"type": "object",
"dynamic": true,
"properties" : {
"id" : {
"type" : "keyword"
},
"key" : {
"type" : "keyword"
},
"self" : {
"type" : "keyword"
}
}
}
}
},
"slack" : {
"type": "object",
"dynamic": true,

View File

@ -52,6 +52,7 @@ public class JiraIssueTests extends ESTestCase {
HttpRequest parsedRequest = null;
HttpResponse parsedResponse = null;
String parsedAccount = null;
String parsedReason = null;
try (XContentParser parser = XContentHelper.createParser(bytes)) {
@ -65,6 +66,8 @@ public class JiraIssueTests extends ESTestCase {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if ("account".equals(currentFieldName)) {
parsedAccount = parser.text();
} else if ("result".equals(currentFieldName)) {
parsedResult = parser.map();
} else if ("request".equals(currentFieldName)) {
@ -83,6 +86,7 @@ public class JiraIssueTests extends ESTestCase {
}
}
assertThat(parsedAccount, equalTo(issue.getAccount()));
assertThat(parsedFields, equalTo(issue.getFields()));
if (issue.successful()) {
assertThat(parsedResult, hasEntry("key", "TEST"));
@ -108,11 +112,12 @@ public class JiraIssueTests extends ESTestCase {
}
}
JiraIssue issue2 = new JiraIssue(fields, issue1.getRequest(), issue1.getResponse(), issue1.getFailureReason());
JiraIssue issue2 = new JiraIssue(issue1.getAccount(), fields, issue1.getRequest(), issue1.getResponse(), issue1.getFailureReason());
assertThat(issue1.equals(issue2), is(equals));
}
private static JiraIssue randomJiraIssue() throws IOException {
String account = "account_" + randomIntBetween(0, 100);
Map<String, Object> fields = randomIssueDefaults();
HttpRequest request = HttpRequest.builder(randomFrom("localhost", "internal-jira.elastic.co"), randomFrom(80, 443))
.method(HttpMethod.POST)
@ -121,8 +126,8 @@ public class JiraIssueTests extends ESTestCase {
.build();
if (rarely()) {
Tuple<Integer, String> error = randomHttpError();
return JiraIssue.responded(fields, request, new HttpResponse(error.v1(), "{\"error\": \"" + error.v2() + "\"}"));
return JiraIssue.responded(account, fields, request, new HttpResponse(error.v1(), "{\"error\": \"" + error.v2() + "\"}"));
}
return JiraIssue.responded(fields, request, new HttpResponse(HttpStatus.SC_CREATED, "{\"key\": \"TEST\"}"));
return JiraIssue.responded(account, fields, request, new HttpResponse(HttpStatus.SC_CREATED, "{\"key\": \"TEST\"}"));
}
}

View File

@ -82,12 +82,40 @@
- match: { hits.hits.0._source.result.actions.0.id: "create_jira_issue" }
- match: { hits.hits.0._source.result.actions.0.type: "jira" }
- match: { hits.hits.0._source.result.actions.0.status: "success" }
- match: { hits.hits.0._source.result.actions.0.jira.account: "test" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.summary: "Hello from jira_watch" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.issuetype.name: "Bug" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.project.key: "BAS" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.labels.0: "integration-tests" }
- match: { hits.hits.0._source.result.actions.0.jira.result.id: /\d+/ }
- match: { hits.hits.0._source.result.actions.0.jira.result.key: /BAS-\d+/ }
- match: { hits.hits.0._source.result.actions.0.jira.result.self: /http(.)*/ }
- set: { hits.hits.0._id: id }
- set: { hits.hits.0._source.result.actions.0.jira.result.self: self }
- do:
search:
index: ".watcher-history-*"
body:
query:
match:
result.actions.jira.fields.project.key: "BAS"
- match: { hits.total: 1 }
- match: { hits.hits.0._id: $id }
- match: { hits.hits.0._source.result.actions.0.jira.result.self: $self }
- do:
search:
index: ".watcher-history-*"
body:
query:
match:
result.actions.jira.fields.summary: "hello jira_watch"
- match: { hits.total: 1 }
- match: { hits.hits.0._id: $id }
- match: { hits.hits.0._source.result.actions.0.jira.result.self: $self }
---
"Test Jira Action with Error":
- do:
@ -137,7 +165,8 @@
"trigger_data" : {
"triggered_time" : "2012-12-12T12:12:12.120Z",
"scheduled_time" : "2000-12-12T12:12:12.120Z"
}
},
"record_execution": true
}
- match: { watch_record.watch_id: "wrong_jira_watch" }
@ -146,14 +175,169 @@
- match: { watch_record.trigger_event.manual.schedule.scheduled_time: "2000-12-12T12:12:12.120Z" }
- match: { watch_record.state: "executed" }
- match: { watch_record.result.actions.0.id: "fail_to_create_jira_issue" }
- match: { watch_record.result.actions.0.type: "jira" }
- match: { watch_record.result.actions.0.status: "failure" }
- match: { watch_record.result.actions.0.jira.fields.summary: "Hello from wrong_jira_watch" }
- is_false: watch_record.result.actions.0.jira.fields.issuetype.name
- match: { watch_record.result.actions.0.jira.fields.project.key: "BAS" }
- match: { watch_record.result.actions.0.jira.fields.labels.0: "integration-tests" }
- match: { watch_record.result.actions.0.jira.reason: "Bad Request - Field [issuetype] has error [issue type is required]\n" }
- match: { watch_record.result.actions.0.jira.request.method: "post" }
- match: { watch_record.result.actions.0.jira.request.path: "/rest/api/2/issue" }
- match: { watch_record.result.actions.0.jira.response.body: "{\"errorMessages\":[],\"errors\":{\"issuetype\":\"issue type is required\"}}" }
# 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:
index: ".watcher-history-*"
body:
query:
match:
result.actions.status: "failure"
- match: { hits.total: 1 }
- match: { hits.hits.0._type: "watch_record" }
- match: { hits.hits.0._source.watch_id: "wrong_jira_watch" }
- match: { hits.hits.0._source.state: "executed" }
- match: { hits.hits.0._source.result.actions.0.id: "fail_to_create_jira_issue" }
- match: { hits.hits.0._source.result.actions.0.type: "jira" }
- match: { hits.hits.0._source.result.actions.0.status: "failure" }
- match: { hits.hits.0._source.result.actions.0.jira.account: "test" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.summary: "Hello from wrong_jira_watch" }
- is_false: hits.hits.0._source.result.actions.0.jira.fields.issuetype.name
- match: { hits.hits.0._source.result.actions.0.jira.fields.project.key: "BAS" }
- match: { hits.hits.0._source.result.actions.0.jira.fields.labels.0: "integration-tests" }
- match: { hits.hits.0._source.result.actions.0.jira.reason: "Bad Request - Field [issuetype] has error [issue type is required]\n" }
- match: { hits.hits.0._source.result.actions.0.jira.request.method: "post" }
- match: { hits.hits.0._source.result.actions.0.jira.request.path: "/rest/api/2/issue" }
- match: { hits.hits.0._source.result.actions.0.jira.request.auth.basic.username: "jira_user" }
- is_false: hits.hits.0._source.result.actions.0.jira.request.auth.basic.password
- match: { hits.hits.0._source.result.actions.0.jira.response.body: "{\"errorMessages\":[],\"errors\":{\"issuetype\":\"issue type is required\"}}" }
---
"Test Jira action with custom fields of different types":
- do:
cluster.health:
wait_for_status: yellow
- do:
xpack.watcher.put_watch:
id: "jira_watch_with_custom_field_one"
body: >
{
"trigger": {
"schedule": {
"interval": "1s"
}
},
"input": {
"simple": {
}
},
"condition": {
"always": {}
},
"actions": {
"create_jira_issue": {
"jira": {
"account": "test",
"fields": {
"summary": "Jira watch with custom field of string type",
"description": "Issue created by the REST integration test [/watcher/actions/10_jira.yaml]",
"issuetype" : {
"name": "Bug"
},
"customfield_70000": "jira-software-users"
}
}
}
}
}
- match: { _id: "jira_watch_with_custom_field_one" }
- match: { created: true }
- do:
xpack.watcher.execute_watch:
id: "jira_watch_with_custom_field_one"
body: >
{
"trigger_data" : {
"triggered_time" : "2012-12-12T12:12:12.120Z",
"scheduled_time" : "2000-12-12T12:12:12.120Z"
},
"record_execution": true
}
- match: { watch_record.watch_id: "jira_watch_with_custom_field_one" }
- match: { watch_record.state: "executed" }
- do:
xpack.watcher.put_watch:
id: "jira_watch_with_custom_field_two"
body: >
{
"trigger": {
"schedule": {
"interval": "1s"
}
},
"input": {
"simple": {
}
},
"condition": {
"always": {}
},
"actions": {
"create_jira_issue": {
"jira": {
"account": "test",
"fields": {
"summary": "Jira watch with custom field of object (Jira's CascadingSelectField) type",
"description": "Issue created by the REST integration test [/watcher/actions/10_jira.yaml]",
"issuetype" : {
"name": "Bug"
},
"customfield_70000": {
"value": "green",
"child": {
"value":"blue"
}
}
}
}
}
}
}
- match: { _id: "jira_watch_with_custom_field_two" }
- match: { created: true }
- do:
xpack.watcher.execute_watch:
id: "jira_watch_with_custom_field_two"
body: >
{
"trigger_data" : {
"triggered_time" : "2012-12-12T12:12:12.120Z",
"scheduled_time" : "2000-12-12T12:12:12.120Z"
},
"record_execution": true
}
- match: { watch_record.watch_id: "jira_watch_with_custom_field_two" }
- match: { watch_record.state: "executed" }
- do:
indices.refresh:
index: ".watcher-history-*"
- do:
search:
index: ".watcher-history-*"
body:
query:
match:
result.actions.status: "failure"
- match: { hits.total: 2 }