Watcher: Provide real watch status on execute watch API (elastic/x-pack-elasticsearch#1076)

When the execute watch API is called without recording the execution
in the watch history, the watch status is not updated, in order to not
divert the in-memory object status and the one persisted on disk.

In order to work around this issue, the execute watch API can simply
clone a new watch status and a new watch, which means the object in
the watch store is never updated. This allows for execution and changing
of the watch status, before it is returned to the client.

relates elastic/x-pack-elasticsearch#889

Original commit: elastic/x-pack-elasticsearch@6a0d9c9a78
This commit is contained in:
Alexander Reelsen 2017-04-13 14:56:14 +01:00 committed by GitHub
parent 450d47d1f5
commit 80e7babe3d
4 changed files with 49 additions and 7 deletions

View File

@ -141,10 +141,8 @@ public abstract class WatchExecutionContext {
public void onConditionResult(Condition.Result conditionResult) { public void onConditionResult(Condition.Result conditionResult) {
assert !phase.sealed(); assert !phase.sealed();
this.conditionResult = conditionResult; this.conditionResult = conditionResult;
if (recordExecution()) {
watch.status().onCheck(conditionResult.met(), executionTime); watch.status().onCheck(conditionResult.met(), executionTime);
} }
}
public Condition.Result conditionResult() { public Condition.Result conditionResult() {
return conditionResult; return conditionResult;
@ -175,10 +173,8 @@ public abstract class WatchExecutionContext {
public void onActionResult(ActionWrapper.Result result) { public void onActionResult(ActionWrapper.Result result) {
assert !phase.sealed(); assert !phase.sealed();
actionsResults.put(result.id(), result); actionsResults.put(result.id(), result);
if (recordExecution()) {
watch.status().onActionResult(result.id(), executionTime, result.action()); watch.status().onActionResult(result.id(), executionTime, result.action());
} }
}
public Map<String, ActionWrapper.Result> actionsResults() { public Map<String, ActionWrapper.Result> actionsResults() {
return Collections.unmodifiableMap(actionsResults); return Collections.unmodifiableMap(actionsResults);

View File

@ -35,6 +35,7 @@ import org.joda.time.DateTimeZone;
import java.time.Clock; import java.time.Clock;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
@ -145,6 +146,13 @@ public class ManualExecutionTests extends AbstractWatcherIntegrationTestCase {
assertThat(response.getStatus().actionStatus("log").ackStatus().state(), assertThat(response.getStatus().actionStatus("log").ackStatus().state(),
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION)); is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
} }
} else {
String ackState = executeWatchResponse.getRecordSource().getValue("_status.actions.log.ack.state");
if (ignoreCondition || conditionAlwaysTrue) {
assertThat(ackState, is(ActionStatus.AckStatus.State.ACKABLE.toString().toLowerCase(Locale.ROOT)));
} else {
assertThat(ackState, is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION.toString().toLowerCase(Locale.ROOT)));
}
} }
} }

View File

@ -81,6 +81,7 @@ public class ExecuteWatchTests extends AbstractWatcherIntegrationTestCase {
assertValue(record, "result.actions.0.type", is("logging")); assertValue(record, "result.actions.0.type", is("logging"));
assertValue(record, "result.actions.0.status", is("success")); assertValue(record, "result.actions.0.status", is("success"));
assertValue(record, "result.actions.0.logging.logged_text", is("_text")); assertValue(record, "result.actions.0.logging.logged_text", is("_text"));
assertValue(record, "_status.actions.log.ack.state", is("ackable"));
} }
public void testExecuteCustomTriggerData() throws Exception { public void testExecuteCustomTriggerData() throws Exception {

View File

@ -32,7 +32,7 @@ teardown:
"actions": { "actions": {
"log" : { "log" : {
"logging" : { "logging" : {
"text" : "execute_watch/10.yaml payload: {{ctx.payload}}" "text" : "execute_watch/10.yaml payload"
} }
} }
} }
@ -57,6 +57,43 @@ teardown:
- match: { watch_record.trigger_event.manual.schedule.scheduled_time: "2000-12-12T12:12:12.120Z" } - match: { watch_record.trigger_event.manual.schedule.scheduled_time: "2000-12-12T12:12:12.120Z" }
- match: { watch_record.state: "executed" } - match: { watch_record.state: "executed" }
- match: { watch_record._status.state.active: true } - match: { watch_record._status.state.active: true }
- match: { watch_record._status.actions.log.ack.state: "ackable" }
---
"Test execute watch API with user supplied watch"
- do:
xpack.watcher.execute_watch:
id: "test_watch"
body: >
{
"watch" : {
"trigger": {
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
},
"input": {
"simple": {
"foo": "bar"
}
},
"condition": {
"always": {}
},
"actions": {
"log" : {
"logging" : {
"text" : "execute_watch/10.yaml payload"
}
}
}
}
}
- match: { watch_record.watch_id: "test_watch" }
- match: { watch_record.trigger_event.type: "manual" }
- match: { watch_record.state: "executed" }
- match: { watch_record._status.state.active: true }
- match: { watch_record._status.actions.log.ack.state: "ackable" }
--- ---
"Execute unknown watch results in 404": "Execute unknown watch results in 404":