Move watcher to use seq# and primary term for concurrency control (#37977)
* move watcher to seq# occ * top level set * fix parsing and missing setters * share toXContent for PutResponse and rest end point * fix redacted password * fix username reference * fix deactivate-watch.asciidoc have seq no references * add seq# + term to activate-watch.asciidoc * more doc fixes
This commit is contained in:
parent
dad41c2b7f
commit
b11732104f
|
@ -76,6 +76,7 @@ import org.elasticsearch.index.reindex.AbstractBulkByScrollRequest;
|
||||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||||
import org.elasticsearch.index.reindex.ReindexRequest;
|
import org.elasticsearch.index.reindex.ReindexRequest;
|
||||||
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||||
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
|
import org.elasticsearch.script.mustache.MultiSearchTemplateRequest;
|
||||||
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
import org.elasticsearch.script.mustache.SearchTemplateRequest;
|
||||||
|
@ -885,6 +886,20 @@ final class RequestConverters {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Params withIfSeqNo(long ifSeqNo) {
|
||||||
|
if (ifSeqNo != SequenceNumbers.UNASSIGNED_SEQ_NO) {
|
||||||
|
return putParam("if_seq_no", Long.toString(ifSeqNo));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Params withIfPrimaryTerm(long ifPrimaryTerm) {
|
||||||
|
if (ifPrimaryTerm != SequenceNumbers.UNASSIGNED_PRIMARY_TERM) {
|
||||||
|
return putParam("if_primary_term", Long.toString(ifPrimaryTerm));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
Params withWaitForActiveShards(ActiveShardCount activeShardCount) {
|
Params withWaitForActiveShards(ActiveShardCount activeShardCount) {
|
||||||
return withWaitForActiveShards(activeShardCount, ActiveShardCount.DEFAULT);
|
return withWaitForActiveShards(activeShardCount, ActiveShardCount.DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,10 @@ final class WatcherRequestConverters {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Request request = new Request(HttpPut.METHOD_NAME, endpoint);
|
Request request = new Request(HttpPut.METHOD_NAME, endpoint);
|
||||||
RequestConverters.Params params = new RequestConverters.Params(request).withVersion(putWatchRequest.getVersion());
|
RequestConverters.Params params = new RequestConverters.Params(request)
|
||||||
|
.withVersion(putWatchRequest.getVersion())
|
||||||
|
.withIfSeqNo(putWatchRequest.ifSeqNo())
|
||||||
|
.withIfPrimaryTerm(putWatchRequest.ifPrimaryTerm());
|
||||||
if (putWatchRequest.isActive() == false) {
|
if (putWatchRequest.isActive() == false) {
|
||||||
params.putParam("active", "false");
|
params.putParam("active", "false");
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,14 @@ import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
|
||||||
public class GetWatchResponse {
|
public class GetWatchResponse {
|
||||||
private final String id;
|
private final String id;
|
||||||
private final long version;
|
private final long version;
|
||||||
|
private final long seqNo;
|
||||||
|
private final long primaryTerm;
|
||||||
private final WatchStatus status;
|
private final WatchStatus status;
|
||||||
|
|
||||||
private final BytesReference source;
|
private final BytesReference source;
|
||||||
|
@ -43,15 +48,18 @@ public class GetWatchResponse {
|
||||||
* Ctor for missing watch
|
* Ctor for missing watch
|
||||||
*/
|
*/
|
||||||
public GetWatchResponse(String id) {
|
public GetWatchResponse(String id) {
|
||||||
this(id, Versions.NOT_FOUND, null, null, null);
|
this(id, Versions.NOT_FOUND, UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GetWatchResponse(String id, long version, WatchStatus status, BytesReference source, XContentType xContentType) {
|
public GetWatchResponse(String id, long version, long seqNo, long primaryTerm, WatchStatus status,
|
||||||
|
BytesReference source, XContentType xContentType) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.xContentType = xContentType;
|
this.xContentType = xContentType;
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -62,6 +70,14 @@ public class GetWatchResponse {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getSeqNo() {
|
||||||
|
return seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPrimaryTerm() {
|
||||||
|
return primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFound() {
|
public boolean isFound() {
|
||||||
return version != Versions.NOT_FOUND;
|
return version != Versions.NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
@ -111,6 +127,8 @@ public class GetWatchResponse {
|
||||||
private static final ParseField ID_FIELD = new ParseField("_id");
|
private static final ParseField ID_FIELD = new ParseField("_id");
|
||||||
private static final ParseField FOUND_FIELD = new ParseField("found");
|
private static final ParseField FOUND_FIELD = new ParseField("found");
|
||||||
private static final ParseField VERSION_FIELD = new ParseField("_version");
|
private static final ParseField VERSION_FIELD = new ParseField("_version");
|
||||||
|
private static final ParseField SEQ_NO_FIELD = new ParseField("_seq_no");
|
||||||
|
private static final ParseField PRIMARY_TERM_FIELD = new ParseField("_primary_term");
|
||||||
private static final ParseField STATUS_FIELD = new ParseField("status");
|
private static final ParseField STATUS_FIELD = new ParseField("status");
|
||||||
private static final ParseField WATCH_FIELD = new ParseField("watch");
|
private static final ParseField WATCH_FIELD = new ParseField("watch");
|
||||||
|
|
||||||
|
@ -119,9 +137,10 @@ public class GetWatchResponse {
|
||||||
a -> {
|
a -> {
|
||||||
boolean isFound = (boolean) a[1];
|
boolean isFound = (boolean) a[1];
|
||||||
if (isFound) {
|
if (isFound) {
|
||||||
XContentBuilder builder = (XContentBuilder) a[4];
|
XContentBuilder builder = (XContentBuilder) a[6];
|
||||||
BytesReference source = BytesReference.bytes(builder);
|
BytesReference source = BytesReference.bytes(builder);
|
||||||
return new GetWatchResponse((String) a[0], (long) a[2], (WatchStatus) a[3], source, builder.contentType());
|
return new GetWatchResponse((String) a[0], (long) a[2], (long) a[3], (long) a[4], (WatchStatus) a[5],
|
||||||
|
source, builder.contentType());
|
||||||
} else {
|
} else {
|
||||||
return new GetWatchResponse((String) a[0]);
|
return new GetWatchResponse((String) a[0]);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +150,8 @@ public class GetWatchResponse {
|
||||||
PARSER.declareString(ConstructingObjectParser.constructorArg(), ID_FIELD);
|
PARSER.declareString(ConstructingObjectParser.constructorArg(), ID_FIELD);
|
||||||
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), FOUND_FIELD);
|
PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), FOUND_FIELD);
|
||||||
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), VERSION_FIELD);
|
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), VERSION_FIELD);
|
||||||
|
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), SEQ_NO_FIELD);
|
||||||
|
PARSER.declareLong(ConstructingObjectParser.optionalConstructorArg(), PRIMARY_TERM_FIELD);
|
||||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(),
|
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(),
|
||||||
(parser, context) -> WatchStatus.parse(parser), STATUS_FIELD);
|
(parser, context) -> WatchStatus.parse(parser), STATUS_FIELD);
|
||||||
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(),
|
PARSER.declareObject(ConstructingObjectParser.optionalConstructorArg(),
|
||||||
|
|
|
@ -23,10 +23,14 @@ import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
import org.elasticsearch.common.lucene.uid.Versions;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This request class contains the data needed to create a watch along with the name of the watch.
|
* This request class contains the data needed to create a watch along with the name of the watch.
|
||||||
* The name of the watch will become the ID of the indexed document.
|
* The name of the watch will become the ID of the indexed document.
|
||||||
|
@ -40,6 +44,9 @@ public final class PutWatchRequest implements Validatable {
|
||||||
private final XContentType xContentType;
|
private final XContentType xContentType;
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
private long version = Versions.MATCH_ANY;
|
private long version = Versions.MATCH_ANY;
|
||||||
|
private long ifSeqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
private long ifPrimaryTerm = UNASSIGNED_PRIMARY_TERM;
|
||||||
|
|
||||||
|
|
||||||
public PutWatchRequest(String id, BytesReference source, XContentType xContentType) {
|
public PutWatchRequest(String id, BytesReference source, XContentType xContentType) {
|
||||||
Objects.requireNonNull(id, "watch id is missing");
|
Objects.requireNonNull(id, "watch id is missing");
|
||||||
|
@ -96,6 +103,56 @@ public final class PutWatchRequest implements Validatable {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only performs this put request if the watch's last modification was assigned the given
|
||||||
|
* sequence number. Must be used in combination with {@link #setIfPrimaryTerm(long)}
|
||||||
|
*
|
||||||
|
* If the watch's last modification was assigned a different sequence number a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public PutWatchRequest setIfSeqNo(long seqNo) {
|
||||||
|
if (seqNo < 0 && seqNo != UNASSIGNED_SEQ_NO) {
|
||||||
|
throw new IllegalArgumentException("sequence numbers must be non negative. got [" + seqNo + "].");
|
||||||
|
}
|
||||||
|
ifSeqNo = seqNo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only performs this put request if the watch's last modification was assigned the given
|
||||||
|
* primary term. Must be used in combination with {@link #setIfSeqNo(long)}
|
||||||
|
*
|
||||||
|
* If the watch last modification was assigned a different term a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public PutWatchRequest setIfPrimaryTerm(long term) {
|
||||||
|
if (term < 0) {
|
||||||
|
throw new IllegalArgumentException("primary term must be non negative. got [" + term + "]");
|
||||||
|
}
|
||||||
|
ifPrimaryTerm = term;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, only perform this put watch request if the watch's last modification was assigned this sequence number.
|
||||||
|
* If the watch last last modification was assigned a different sequence number a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public long ifSeqNo() {
|
||||||
|
return ifSeqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, only perform this put watch request if the watch's last modification was assigned this primary term.
|
||||||
|
*
|
||||||
|
* If the watch's last modification was assigned a different term a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public long ifPrimaryTerm() {
|
||||||
|
return ifPrimaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean isValidId(String id) {
|
public static boolean isValidId(String id) {
|
||||||
return Strings.isEmpty(id) == false && NO_WS_PATTERN.matcher(id).matches();
|
return Strings.isEmpty(id) == false && NO_WS_PATTERN.matcher(id).matches();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.client.watcher;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -32,20 +33,26 @@ public class PutWatchResponse {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
PARSER.declareString(PutWatchResponse::setId, new ParseField("_id"));
|
PARSER.declareString(PutWatchResponse::setId, new ParseField("_id"));
|
||||||
|
PARSER.declareLong(PutWatchResponse::setSeqNo, new ParseField("_seq_no"));
|
||||||
|
PARSER.declareLong(PutWatchResponse::setPrimaryTerm, new ParseField("_primary_term"));
|
||||||
PARSER.declareLong(PutWatchResponse::setVersion, new ParseField("_version"));
|
PARSER.declareLong(PutWatchResponse::setVersion, new ParseField("_version"));
|
||||||
PARSER.declareBoolean(PutWatchResponse::setCreated, new ParseField("created"));
|
PARSER.declareBoolean(PutWatchResponse::setCreated, new ParseField("created"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private long version;
|
private long version;
|
||||||
|
private long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
private long primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
private boolean created;
|
private boolean created;
|
||||||
|
|
||||||
public PutWatchResponse() {
|
public PutWatchResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PutWatchResponse(String id, long version, boolean created) {
|
public PutWatchResponse(String id, long version, long seqNo, long primaryTerm, boolean created) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +64,14 @@ public class PutWatchResponse {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSeqNo(long seqNo) {
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPrimaryTerm(long primaryTerm) {
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
private void setCreated(boolean created) {
|
private void setCreated(boolean created) {
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +84,14 @@ public class PutWatchResponse {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getSeqNo() {
|
||||||
|
return seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPrimaryTerm() {
|
||||||
|
return primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCreated() {
|
public boolean isCreated() {
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
@ -80,12 +103,14 @@ public class PutWatchResponse {
|
||||||
|
|
||||||
PutWatchResponse that = (PutWatchResponse) o;
|
PutWatchResponse that = (PutWatchResponse) o;
|
||||||
|
|
||||||
return Objects.equals(id, that.id) && Objects.equals(version, that.version) && Objects.equals(created, that.created);
|
return Objects.equals(id, that.id) && Objects.equals(version, that.version)
|
||||||
|
&& Objects.equals(seqNo, that.seqNo)
|
||||||
|
&& Objects.equals(primaryTerm, that.primaryTerm) && Objects.equals(created, that.created);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(id, version, created);
|
return Objects.hash(id, version, seqNo, primaryTerm, created);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PutWatchResponse fromXContent(XContentParser parser) throws IOException {
|
public static PutWatchResponse fromXContent(XContentParser parser) throws IOException {
|
||||||
|
|
|
@ -41,14 +41,18 @@ public class PutWatchResponseTests extends ESTestCase {
|
||||||
return builder.startObject()
|
return builder.startObject()
|
||||||
.field("_id", response.getId())
|
.field("_id", response.getId())
|
||||||
.field("_version", response.getVersion())
|
.field("_version", response.getVersion())
|
||||||
|
.field("_seq_no", response.getSeqNo())
|
||||||
|
.field("_primary_term", response.getPrimaryTerm())
|
||||||
.field("created", response.isCreated())
|
.field("created", response.isCreated())
|
||||||
.endObject();
|
.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PutWatchResponse createTestInstance() {
|
private static PutWatchResponse createTestInstance() {
|
||||||
String id = randomAlphaOfLength(10);
|
String id = randomAlphaOfLength(10);
|
||||||
|
long seqNo = randomNonNegativeLong();
|
||||||
|
long primaryTerm = randomLongBetween(1, 200);
|
||||||
long version = randomLongBetween(1, 10);
|
long version = randomLongBetween(1, 10);
|
||||||
boolean created = randomBoolean();
|
boolean created = randomBoolean();
|
||||||
return new PutWatchResponse(id, version, created);
|
return new PutWatchResponse(id, version, seqNo, primaryTerm, created);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,8 @@ The action state of a newly-created watch is `awaits_successful_execution`:
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
|
"_seq_no": 0,
|
||||||
|
"_primary_term": 1,
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
"status": {
|
"status": {
|
||||||
|
@ -136,6 +138,8 @@ and the action is now in `ackable` state:
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
|
"_seq_no": 1,
|
||||||
|
"_primary_term": 1,
|
||||||
"_version": 2,
|
"_version": 2,
|
||||||
"status": {
|
"status": {
|
||||||
"version": 2,
|
"version": 2,
|
||||||
|
@ -185,6 +189,8 @@ GET _watcher/watch/my_watch
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
|
"_seq_no": 2,
|
||||||
|
"_primary_term": 1,
|
||||||
"_version": 3,
|
"_version": 3,
|
||||||
"status": {
|
"status": {
|
||||||
"version": 3,
|
"version": 3,
|
||||||
|
|
|
@ -44,6 +44,8 @@ GET _watcher/watch/my_watch
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
|
"_seq_no": 0,
|
||||||
|
"_primary_term": 1,
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
"status": {
|
"status": {
|
||||||
"state" : {
|
"state" : {
|
||||||
|
|
|
@ -44,6 +44,8 @@ GET _watcher/watch/my_watch
|
||||||
"found": true,
|
"found": true,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
|
"_seq_no": 0,
|
||||||
|
"_primary_term": 1,
|
||||||
"status": {
|
"status": {
|
||||||
"state" : {
|
"state" : {
|
||||||
"active" : true,
|
"active" : true,
|
||||||
|
|
|
@ -44,6 +44,8 @@ Response:
|
||||||
{
|
{
|
||||||
"found": true,
|
"found": true,
|
||||||
"_id": "my_watch",
|
"_id": "my_watch",
|
||||||
|
"_seq_no": 0,
|
||||||
|
"_primary_term": 1,
|
||||||
"_version": 1,
|
"_version": 1,
|
||||||
"status": { <1>
|
"status": { <1>
|
||||||
"version": 1,
|
"version": 1,
|
||||||
|
|
|
@ -5,19 +5,24 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.protocol.xpack.watcher;
|
package org.elasticsearch.protocol.xpack.watcher;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ValidateActions;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
import org.elasticsearch.common.lucene.uid.Versions;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This request class contains the data needed to create a watch along with the name of the watch.
|
* This request class contains the data needed to create a watch along with the name of the watch.
|
||||||
* The name of the watch will become the ID of the indexed document.
|
* The name of the watch will become the ID of the indexed document.
|
||||||
|
@ -32,6 +37,9 @@ public final class PutWatchRequest extends ActionRequest {
|
||||||
private boolean active = true;
|
private boolean active = true;
|
||||||
private long version = Versions.MATCH_ANY;
|
private long version = Versions.MATCH_ANY;
|
||||||
|
|
||||||
|
private long ifSeqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
private long ifPrimaryTerm = UNASSIGNED_PRIMARY_TERM;
|
||||||
|
|
||||||
public PutWatchRequest() {}
|
public PutWatchRequest() {}
|
||||||
|
|
||||||
public PutWatchRequest(StreamInput in) throws IOException {
|
public PutWatchRequest(StreamInput in) throws IOException {
|
||||||
|
@ -52,6 +60,13 @@ public final class PutWatchRequest extends ActionRequest {
|
||||||
active = in.readBoolean();
|
active = in.readBoolean();
|
||||||
xContentType = in.readEnum(XContentType.class);
|
xContentType = in.readEnum(XContentType.class);
|
||||||
version = in.readZLong();
|
version = in.readZLong();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
ifSeqNo = in.readZLong();
|
||||||
|
ifPrimaryTerm = in.readVLong();
|
||||||
|
} else {
|
||||||
|
ifSeqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
ifPrimaryTerm = UNASSIGNED_PRIMARY_TERM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,6 +77,10 @@ public final class PutWatchRequest extends ActionRequest {
|
||||||
out.writeBoolean(active);
|
out.writeBoolean(active);
|
||||||
out.writeEnum(xContentType);
|
out.writeEnum(xContentType);
|
||||||
out.writeZLong(version);
|
out.writeZLong(version);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
out.writeZLong(ifSeqNo);
|
||||||
|
out.writeVLong(ifPrimaryTerm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,20 +141,80 @@ public final class PutWatchRequest extends ActionRequest {
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only performs this put request if the watch's last modification was assigned the given
|
||||||
|
* sequence number. Must be used in combination with {@link #setIfPrimaryTerm(long)}
|
||||||
|
*
|
||||||
|
* If the watch's last modification was assigned a different sequence number a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public PutWatchRequest setIfSeqNo(long seqNo) {
|
||||||
|
if (seqNo < 0 && seqNo != UNASSIGNED_SEQ_NO) {
|
||||||
|
throw new IllegalArgumentException("sequence numbers must be non negative. got [" + seqNo + "].");
|
||||||
|
}
|
||||||
|
ifSeqNo = seqNo;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only performs this put request if the watch's last modification was assigned the given
|
||||||
|
* primary term. Must be used in combination with {@link #setIfSeqNo(long)}
|
||||||
|
*
|
||||||
|
* If the watch last modification was assigned a different term a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public PutWatchRequest setIfPrimaryTerm(long term) {
|
||||||
|
if (term < 0) {
|
||||||
|
throw new IllegalArgumentException("primary term must be non negative. got [" + term + "]");
|
||||||
|
}
|
||||||
|
ifPrimaryTerm = term;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, only perform this put watch request if the watch's last modification was assigned this sequence number.
|
||||||
|
* If the watch last last modification was assigned a different sequence number a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public long getIfSeqNo() {
|
||||||
|
return ifSeqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set, only perform this put watch request if the watch's last modification was assigned this primary term.
|
||||||
|
*
|
||||||
|
* If the watch's last modification was assigned a different term a
|
||||||
|
* {@link org.elasticsearch.index.engine.VersionConflictEngineException} will be thrown.
|
||||||
|
*/
|
||||||
|
public long getIfPrimaryTerm() {
|
||||||
|
return ifPrimaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionRequestValidationException validate() {
|
public ActionRequestValidationException validate() {
|
||||||
ActionRequestValidationException validationException = null;
|
ActionRequestValidationException validationException = null;
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
validationException = ValidateActions.addValidationError("watch id is missing", validationException);
|
validationException = addValidationError("watch id is missing", validationException);
|
||||||
} else if (isValidId(id) == false) {
|
} else if (isValidId(id) == false) {
|
||||||
validationException = ValidateActions.addValidationError("watch id contains whitespace", validationException);
|
validationException = addValidationError("watch id contains whitespace", validationException);
|
||||||
}
|
}
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
validationException = ValidateActions.addValidationError("watch source is missing", validationException);
|
validationException = addValidationError("watch source is missing", validationException);
|
||||||
}
|
}
|
||||||
if (xContentType == null) {
|
if (xContentType == null) {
|
||||||
validationException = ValidateActions.addValidationError("request body is missing", validationException);
|
validationException = addValidationError("request body is missing", validationException);
|
||||||
}
|
}
|
||||||
|
if (ifSeqNo != UNASSIGNED_SEQ_NO && version != Versions.MATCH_ANY) {
|
||||||
|
validationException = addValidationError("compare and write operations can not use versioning", validationException);
|
||||||
|
}
|
||||||
|
if (ifPrimaryTerm == UNASSIGNED_PRIMARY_TERM && ifSeqNo != UNASSIGNED_SEQ_NO) {
|
||||||
|
validationException = addValidationError("ifSeqNo is set, but primary term is [0]", validationException);
|
||||||
|
}
|
||||||
|
if (ifPrimaryTerm != UNASSIGNED_PRIMARY_TERM && ifSeqNo == UNASSIGNED_SEQ_NO) {
|
||||||
|
validationException =
|
||||||
|
addValidationError("ifSeqNo is unassigned, but primary term is [" + ifPrimaryTerm + "]", validationException);
|
||||||
|
}
|
||||||
|
|
||||||
return validationException;
|
return validationException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.protocol.xpack.watcher;
|
package org.elasticsearch.protocol.xpack.watcher;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
@ -13,6 +14,7 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -24,19 +26,25 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
static {
|
static {
|
||||||
PARSER.declareString(PutWatchResponse::setId, new ParseField("_id"));
|
PARSER.declareString(PutWatchResponse::setId, new ParseField("_id"));
|
||||||
PARSER.declareLong(PutWatchResponse::setVersion, new ParseField("_version"));
|
PARSER.declareLong(PutWatchResponse::setVersion, new ParseField("_version"));
|
||||||
|
PARSER.declareLong(PutWatchResponse::setSeqNo, new ParseField("_seq_no"));
|
||||||
|
PARSER.declareLong(PutWatchResponse::setPrimaryTerm, new ParseField("_primary_term"));
|
||||||
PARSER.declareBoolean(PutWatchResponse::setCreated, new ParseField("created"));
|
PARSER.declareBoolean(PutWatchResponse::setCreated, new ParseField("created"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private long version;
|
private long version;
|
||||||
|
private long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
private long primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
private boolean created;
|
private boolean created;
|
||||||
|
|
||||||
public PutWatchResponse() {
|
public PutWatchResponse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PutWatchResponse(String id, long version, boolean created) {
|
public PutWatchResponse(String id, long version, long seqNo, long primaryTerm, boolean created) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +56,14 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSeqNo(long seqNo) {
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPrimaryTerm(long primaryTerm) {
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
private void setCreated(boolean created) {
|
private void setCreated(boolean created) {
|
||||||
this.created = created;
|
this.created = created;
|
||||||
}
|
}
|
||||||
|
@ -60,6 +76,14 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getSeqNo() {
|
||||||
|
return seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPrimaryTerm() {
|
||||||
|
return primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCreated() {
|
public boolean isCreated() {
|
||||||
return created;
|
return created;
|
||||||
}
|
}
|
||||||
|
@ -71,12 +95,14 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
|
|
||||||
PutWatchResponse that = (PutWatchResponse) o;
|
PutWatchResponse that = (PutWatchResponse) o;
|
||||||
|
|
||||||
return Objects.equals(id, that.id) && Objects.equals(version, that.version) && Objects.equals(created, that.created);
|
return Objects.equals(id, that.id) && Objects.equals(version, that.version)
|
||||||
|
&& Objects.equals(seqNo, that.seqNo)
|
||||||
|
&& Objects.equals(primaryTerm, that.primaryTerm) && Objects.equals(created, that.created);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(id, version, created);
|
return Objects.hash(id, version, seqNo, primaryTerm, created);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,6 +110,10 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
out.writeString(id);
|
out.writeString(id);
|
||||||
out.writeVLong(version);
|
out.writeVLong(version);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
out.writeZLong(seqNo);
|
||||||
|
out.writeVLong(primaryTerm);
|
||||||
|
}
|
||||||
out.writeBoolean(created);
|
out.writeBoolean(created);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +122,13 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
super.readFrom(in);
|
super.readFrom(in);
|
||||||
id = in.readString();
|
id = in.readString();
|
||||||
version = in.readVLong();
|
version = in.readVLong();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
seqNo = in.readZLong();
|
||||||
|
primaryTerm = in.readVLong();
|
||||||
|
} else {
|
||||||
|
seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
|
}
|
||||||
created = in.readBoolean();
|
created = in.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +137,8 @@ public class PutWatchResponse extends ActionResponse implements ToXContentObject
|
||||||
return builder.startObject()
|
return builder.startObject()
|
||||||
.field("_id", id)
|
.field("_id", id)
|
||||||
.field("_version", version)
|
.field("_version", version)
|
||||||
|
.field("_seq_no", seqNo)
|
||||||
|
.field("_primary_term", primaryTerm)
|
||||||
.field("created", created)
|
.field("created", created)
|
||||||
.endObject();
|
.endObject();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.core.watcher.transport.actions.get;
|
package org.elasticsearch.xpack.core.watcher.transport.actions.get;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
@ -12,6 +13,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
import org.elasticsearch.common.lucene.uid.Versions;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource;
|
import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource;
|
||||||
import org.elasticsearch.xpack.core.watcher.watch.WatchStatus;
|
import org.elasticsearch.xpack.core.watcher.watch.WatchStatus;
|
||||||
|
|
||||||
|
@ -25,6 +27,8 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
private boolean found;
|
private boolean found;
|
||||||
private XContentSource source;
|
private XContentSource source;
|
||||||
private long version;
|
private long version;
|
||||||
|
private long seqNo;
|
||||||
|
private long primaryTerm;
|
||||||
|
|
||||||
public GetWatchResponse() {
|
public GetWatchResponse() {
|
||||||
}
|
}
|
||||||
|
@ -38,17 +42,21 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
this.found = false;
|
this.found = false;
|
||||||
this.source = null;
|
this.source = null;
|
||||||
this.version = Versions.NOT_FOUND;
|
this.version = Versions.NOT_FOUND;
|
||||||
|
this.seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
this.primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ctor for found watch
|
* ctor for found watch
|
||||||
*/
|
*/
|
||||||
public GetWatchResponse(String id, long version, WatchStatus status, XContentSource source) {
|
public GetWatchResponse(String id, long version, long seqNo, long primaryTerm, WatchStatus status, XContentSource source) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.found = true;
|
this.found = true;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
|
this.seqNo = seqNo;
|
||||||
|
this.primaryTerm = primaryTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
@ -71,6 +79,14 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getSeqNo() {
|
||||||
|
return seqNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getPrimaryTerm() {
|
||||||
|
return primaryTerm;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readFrom(StreamInput in) throws IOException {
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
super.readFrom(in);
|
super.readFrom(in);
|
||||||
|
@ -80,10 +96,16 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
status = WatchStatus.read(in);
|
status = WatchStatus.read(in);
|
||||||
source = XContentSource.readFrom(in);
|
source = XContentSource.readFrom(in);
|
||||||
version = in.readZLong();
|
version = in.readZLong();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
seqNo = in.readZLong();
|
||||||
|
primaryTerm = in.readVLong();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
status = null;
|
status = null;
|
||||||
source = null;
|
source = null;
|
||||||
version = Versions.NOT_FOUND;
|
version = Versions.NOT_FOUND;
|
||||||
|
seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
primaryTerm = SequenceNumbers.UNASSIGNED_PRIMARY_TERM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +118,10 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
status.writeTo(out);
|
status.writeTo(out);
|
||||||
XContentSource.writeTo(source, out);
|
XContentSource.writeTo(source, out);
|
||||||
out.writeZLong(version);
|
out.writeZLong(version);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
out.writeZLong(seqNo);
|
||||||
|
out.writeVLong(primaryTerm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +131,8 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
builder.field("_id", id);
|
builder.field("_id", id);
|
||||||
if (found) {
|
if (found) {
|
||||||
builder.field("_version", version);
|
builder.field("_version", version);
|
||||||
|
builder.field("_seq_no", seqNo);
|
||||||
|
builder.field("_primary_term", primaryTerm);
|
||||||
builder.field("status", status, params);
|
builder.field("status", status, params);
|
||||||
builder.field("watch", source, params);
|
builder.field("watch", source, params);
|
||||||
}
|
}
|
||||||
|
@ -116,7 +144,7 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
GetWatchResponse that = (GetWatchResponse) o;
|
GetWatchResponse that = (GetWatchResponse) o;
|
||||||
return version == that.version &&
|
return version == that.version && seqNo == that.seqNo && primaryTerm == that.primaryTerm &&
|
||||||
Objects.equals(id, that.id) &&
|
Objects.equals(id, that.id) &&
|
||||||
Objects.equals(status, that.status) &&
|
Objects.equals(status, that.status) &&
|
||||||
Objects.equals(source, that.source);
|
Objects.equals(source, that.source);
|
||||||
|
@ -124,7 +152,7 @@ public class GetWatchResponse extends ActionResponse implements ToXContent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(id, status, version);
|
return Objects.hash(id, status, version, seqNo, primaryTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.xpack.core.watcher.actions.ActionStatus;
|
import org.elasticsearch.xpack.core.watcher.actions.ActionStatus;
|
||||||
import org.elasticsearch.xpack.core.watcher.actions.ActionWrapper;
|
import org.elasticsearch.xpack.core.watcher.actions.ActionWrapper;
|
||||||
import org.elasticsearch.xpack.core.watcher.condition.ExecutableCondition;
|
import org.elasticsearch.xpack.core.watcher.condition.ExecutableCondition;
|
||||||
|
@ -37,11 +38,12 @@ public class Watch implements ToXContentObject {
|
||||||
@Nullable private final Map<String, Object> metadata;
|
@Nullable private final Map<String, Object> metadata;
|
||||||
private final WatchStatus status;
|
private final WatchStatus status;
|
||||||
|
|
||||||
private transient long version;
|
private final long sourceSeqNo;
|
||||||
|
private final long sourcePrimaryTerm;
|
||||||
|
|
||||||
public Watch(String id, Trigger trigger, ExecutableInput input, ExecutableCondition condition, @Nullable ExecutableTransform transform,
|
public Watch(String id, Trigger trigger, ExecutableInput input, ExecutableCondition condition, @Nullable ExecutableTransform transform,
|
||||||
@Nullable TimeValue throttlePeriod, List<ActionWrapper> actions, @Nullable Map<String, Object> metadata,
|
@Nullable TimeValue throttlePeriod, List<ActionWrapper> actions, @Nullable Map<String, Object> metadata,
|
||||||
WatchStatus status, long version) {
|
WatchStatus status, long sourceSeqNo, long sourcePrimaryTerm) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.trigger = trigger;
|
this.trigger = trigger;
|
||||||
this.input = input;
|
this.input = input;
|
||||||
|
@ -51,7 +53,8 @@ public class Watch implements ToXContentObject {
|
||||||
this.throttlePeriod = throttlePeriod;
|
this.throttlePeriod = throttlePeriod;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.version = version;
|
this.sourceSeqNo = sourceSeqNo;
|
||||||
|
this.sourcePrimaryTerm = sourcePrimaryTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String id() {
|
public String id() {
|
||||||
|
@ -88,12 +91,20 @@ public class Watch implements ToXContentObject {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long version() {
|
/**
|
||||||
return version;
|
* The sequence number of the document that was used to create this watch, {@link SequenceNumbers#UNASSIGNED_SEQ_NO}
|
||||||
|
* if the watch wasn't read from a document
|
||||||
|
***/
|
||||||
|
public long getSourceSeqNo() {
|
||||||
|
return sourceSeqNo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void version(long version) {
|
/**
|
||||||
this.version = version;
|
* The primary term of the document that was used to create this watch, {@link SequenceNumbers#UNASSIGNED_PRIMARY_TERM}
|
||||||
|
* if the watch wasn't read from a document
|
||||||
|
***/
|
||||||
|
public long getSourcePrimaryTerm() {
|
||||||
|
return sourcePrimaryTerm;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,7 +17,6 @@ public final class WatchField {
|
||||||
public static final ParseField THROTTLE_PERIOD_HUMAN = new ParseField("throttle_period");
|
public static final ParseField THROTTLE_PERIOD_HUMAN = new ParseField("throttle_period");
|
||||||
public static final ParseField METADATA = new ParseField("metadata");
|
public static final ParseField METADATA = new ParseField("metadata");
|
||||||
public static final ParseField STATUS = new ParseField("status");
|
public static final ParseField STATUS = new ParseField("status");
|
||||||
public static final ParseField VERSION = new ParseField("_version");
|
|
||||||
public static final String ALL_ACTIONS_ID = "_all";
|
public static final String ALL_ACTIONS_ID = "_all";
|
||||||
|
|
||||||
private WatchField() {}
|
private WatchField() {}
|
||||||
|
|
|
@ -74,6 +74,7 @@ public class GetWatchResponseTests extends
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
newInstance = new GetWatchResponse(newInstance.getId(), newInstance.getVersion(),
|
newInstance = new GetWatchResponse(newInstance.getId(), newInstance.getVersion(),
|
||||||
|
newInstance.getSeqNo(), newInstance.getPrimaryTerm(),
|
||||||
newInstance.getStatus(), new XContentSource(newSource, expectedInstance.getSource().getContentType()));
|
newInstance.getStatus(), new XContentSource(newSource, expectedInstance.getSource().getContentType()));
|
||||||
}
|
}
|
||||||
super.assertEqualInstances(expectedInstance, newInstance);
|
super.assertEqualInstances(expectedInstance, newInstance);
|
||||||
|
@ -91,9 +92,11 @@ public class GetWatchResponseTests extends
|
||||||
return new GetWatchResponse(id);
|
return new GetWatchResponse(id);
|
||||||
}
|
}
|
||||||
long version = randomLongBetween(0, 10);
|
long version = randomLongBetween(0, 10);
|
||||||
|
long seqNo = randomNonNegativeLong();
|
||||||
|
long primaryTerm = randomLongBetween(1, 2000);
|
||||||
WatchStatus status = randomWatchStatus();
|
WatchStatus status = randomWatchStatus();
|
||||||
BytesReference source = simpleWatch();
|
BytesReference source = simpleWatch();
|
||||||
return new GetWatchResponse(id, version, status, new XContentSource(source, XContentType.JSON));
|
return new GetWatchResponse(id, version, seqNo, primaryTerm, status, new XContentSource(source, XContentType.JSON));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BytesReference simpleWatch() {
|
private static BytesReference simpleWatch() {
|
||||||
|
@ -170,8 +173,8 @@ public class GetWatchResponseTests extends
|
||||||
@Override
|
@Override
|
||||||
public GetWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.GetWatchResponse instance) {
|
public GetWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.GetWatchResponse instance) {
|
||||||
if (instance.isFound()) {
|
if (instance.isFound()) {
|
||||||
return new GetWatchResponse(instance.getId(), instance.getVersion(), convertHlrcToInternal(instance.getStatus()),
|
return new GetWatchResponse(instance.getId(), instance.getVersion(), instance.getSeqNo(), instance.getPrimaryTerm(),
|
||||||
new XContentSource(instance.getSource(), instance.getContentType()));
|
convertHlrcToInternal(instance.getStatus()), new XContentSource(instance.getSource(), instance.getContentType()));
|
||||||
} else {
|
} else {
|
||||||
return new GetWatchResponse(instance.getId());
|
return new GetWatchResponse(instance.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@ public class PutWatchResponseTests extends
|
||||||
@Override
|
@Override
|
||||||
protected PutWatchResponse createTestInstance() {
|
protected PutWatchResponse createTestInstance() {
|
||||||
String id = randomAlphaOfLength(10);
|
String id = randomAlphaOfLength(10);
|
||||||
|
long seqNo = randomNonNegativeLong();
|
||||||
|
long primaryTerm = randomLongBetween(1, 20);
|
||||||
long version = randomLongBetween(1, 10);
|
long version = randomLongBetween(1, 10);
|
||||||
boolean created = randomBoolean();
|
boolean created = randomBoolean();
|
||||||
return new PutWatchResponse(id, version, created);
|
return new PutWatchResponse(id, version, seqNo, primaryTerm, created);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -33,7 +35,8 @@ public class PutWatchResponseTests extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PutWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.PutWatchResponse instance) {
|
public PutWatchResponse convertHlrcToInternal(org.elasticsearch.client.watcher.PutWatchResponse instance) {
|
||||||
return new PutWatchResponse(instance.getId(), instance.getVersion(), instance.isCreated());
|
return new PutWatchResponse(instance.getId(), instance.getVersion(), instance.getSeqNo(), instance.getPrimaryTerm(),
|
||||||
|
instance.isCreated());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
"version" : {
|
"version" : {
|
||||||
"type" : "number",
|
"type" : "number",
|
||||||
"description" : "Explicit version number for concurrency control"
|
"description" : "Explicit version number for concurrency control"
|
||||||
|
},
|
||||||
|
"if_seq_no" : {
|
||||||
|
"type" : "number",
|
||||||
|
"description" : "only update the watch if the last operation that has changed the watch has the specified sequence number"
|
||||||
|
},
|
||||||
|
"if_primary_term" : {
|
||||||
|
"type" : "number",
|
||||||
|
"description" : "only update the watch if the last operation that has changed the watch has the specified primary term"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -221,6 +221,175 @@ setup:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test putting a watch with a redacted password with old seq no returns an error":
|
||||||
|
- skip:
|
||||||
|
version: " - 6.99.99"
|
||||||
|
reason: seq no powered concurrency was added in 7.0.0
|
||||||
|
|
||||||
|
# version 1
|
||||||
|
- do:
|
||||||
|
xpack.watcher.put_watch:
|
||||||
|
id: "watch_with_seq_no"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"http" : {
|
||||||
|
"request" : {
|
||||||
|
"host" : "host.domain",
|
||||||
|
"port" : 9200,
|
||||||
|
"path" : "/myservice",
|
||||||
|
"auth" : {
|
||||||
|
"basic" : {
|
||||||
|
"username" : "user",
|
||||||
|
"password" : "pass"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"logging": {
|
||||||
|
"logging": {
|
||||||
|
"text": "Log me Amadeus!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- set: { "_seq_no": seqNo }
|
||||||
|
- set: { "_primary_term" : primaryTerm }
|
||||||
|
|
||||||
|
# using optimistic concurrency control, this one will loose
|
||||||
|
# as if two users in the watch UI tried to update the same watch
|
||||||
|
- do:
|
||||||
|
catch: conflict
|
||||||
|
xpack.watcher.put_watch:
|
||||||
|
id: "watch_with_seq_no"
|
||||||
|
if_seq_no: 123034
|
||||||
|
if_primary_term: $primaryTerm
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"http" : {
|
||||||
|
"request" : {
|
||||||
|
"host" : "host.domain",
|
||||||
|
"port" : 9200,
|
||||||
|
"path" : "/myservice",
|
||||||
|
"auth" : {
|
||||||
|
"basic" : {
|
||||||
|
"username" : "user",
|
||||||
|
"password" : "::es_redacted::"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"logging": {
|
||||||
|
"logging": {
|
||||||
|
"text": "Log me Amadeus!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: conflict
|
||||||
|
xpack.watcher.put_watch:
|
||||||
|
id: "watch_with_seq_no"
|
||||||
|
if_seq_no: $seqNo
|
||||||
|
if_primary_term: 234242423
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"http" : {
|
||||||
|
"request" : {
|
||||||
|
"host" : "host.domain",
|
||||||
|
"port" : 9200,
|
||||||
|
"path" : "/myservice",
|
||||||
|
"auth" : {
|
||||||
|
"basic" : {
|
||||||
|
"username" : "user",
|
||||||
|
"password" : "::es_redacted::"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"logging": {
|
||||||
|
"logging": {
|
||||||
|
"text": "Log me Amadeus!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.watcher.put_watch:
|
||||||
|
id: "watch_with_seq_no"
|
||||||
|
if_seq_no: $seqNo
|
||||||
|
if_primary_term: $primaryTerm
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"schedule" : { "cron" : "0 0 0 1 * ? 2099" }
|
||||||
|
},
|
||||||
|
"input": {
|
||||||
|
"http" : {
|
||||||
|
"request" : {
|
||||||
|
"host" : "host.domain",
|
||||||
|
"port" : 9200,
|
||||||
|
"path" : "/myservice",
|
||||||
|
"auth" : {
|
||||||
|
"basic" : {
|
||||||
|
"username" : "new_user",
|
||||||
|
"password" : "::es_redacted::"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"logging": {
|
||||||
|
"logging": {
|
||||||
|
"text": "Log me Amadeus!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
search:
|
||||||
|
rest_total_hits_as_int: true
|
||||||
|
index: .watches
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"query": {
|
||||||
|
"term": {
|
||||||
|
"_id": {
|
||||||
|
"value": "watch_with_seq_no"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- match: { hits.total: 1 }
|
||||||
|
- match: { hits.hits.0._id: "watch_with_seq_no" }
|
||||||
|
- match: { hits.hits.0._source.input.http.request.auth.basic.username: "new_user" }
|
||||||
|
- match: { hits.hits.0._source.input.http.request.auth.basic.password: "pass" }
|
||||||
|
|
||||||
---
|
---
|
||||||
"Test putting a watch with a redacted password with current version works":
|
"Test putting a watch with a redacted password with current version works":
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,8 @@ final class WatcherIndexingListener implements IndexingOperationListener, Cluste
|
||||||
if (isWatchDocument(shardId.getIndexName(), operation.type())) {
|
if (isWatchDocument(shardId.getIndexName(), operation.type())) {
|
||||||
DateTime now = new DateTime(clock.millis(), UTC);
|
DateTime now = new DateTime(clock.millis(), UTC);
|
||||||
try {
|
try {
|
||||||
Watch watch = parser.parseWithSecrets(operation.id(), true, operation.source(), now, XContentType.JSON);
|
Watch watch = parser.parseWithSecrets(operation.id(), true, operation.source(), now, XContentType.JSON,
|
||||||
|
operation.getIfSeqNo(), operation.getIfPrimaryTerm());
|
||||||
ShardAllocationConfiguration shardAllocationConfiguration = configuration.localShards.get(shardId);
|
ShardAllocationConfiguration shardAllocationConfiguration = configuration.localShards.get(shardId);
|
||||||
if (shardAllocationConfiguration == null) {
|
if (shardAllocationConfiguration == null) {
|
||||||
logger.debug("no distributed watch execution info found for watch [{}] on shard [{}], got configuration for {}",
|
logger.debug("no distributed watch execution info found for watch [{}] on shard [{}], got configuration for {}",
|
||||||
|
|
|
@ -298,7 +298,7 @@ public class WatcherService {
|
||||||
.source(new SearchSourceBuilder()
|
.source(new SearchSourceBuilder()
|
||||||
.size(scrollSize)
|
.size(scrollSize)
|
||||||
.sort(SortBuilders.fieldSort("_doc"))
|
.sort(SortBuilders.fieldSort("_doc"))
|
||||||
.version(true));
|
.seqNoAndPrimaryTerm(true));
|
||||||
response = client.search(searchRequest).actionGet(defaultSearchTimeout);
|
response = client.search(searchRequest).actionGet(defaultSearchTimeout);
|
||||||
|
|
||||||
if (response.getTotalShards() != response.getSuccessfulShards()) {
|
if (response.getTotalShards() != response.getSuccessfulShards()) {
|
||||||
|
@ -341,8 +341,7 @@ public class WatcherService {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Watch watch = parser.parse(id, true, hit.getSourceRef(), XContentType.JSON);
|
Watch watch = parser.parse(id, true, hit.getSourceRef(), XContentType.JSON, hit.getSeqNo(), hit.getPrimaryTerm());
|
||||||
watch.version(hit.getVersion());
|
|
||||||
if (watch.status().state().isActive()) {
|
if (watch.status().state().isActive()) {
|
||||||
watches.add(watch);
|
watches.add(watch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -282,7 +282,8 @@ public class ExecutionService {
|
||||||
if (resp.isExists() == false) {
|
if (resp.isExists() == false) {
|
||||||
throw new ResourceNotFoundException("watch [{}] does not exist", watchId);
|
throw new ResourceNotFoundException("watch [{}] does not exist", watchId);
|
||||||
}
|
}
|
||||||
return parser.parseWithSecrets(watchId, true, resp.getSourceAsBytesRef(), ctx.executionTime(), XContentType.JSON);
|
return parser.parseWithSecrets(watchId, true, resp.getSourceAsBytesRef(), ctx.executionTime(), XContentType.JSON,
|
||||||
|
resp.getSeqNo(), resp.getPrimaryTerm());
|
||||||
});
|
});
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
String message = "unable to find watch for record [" + ctx.id() + "]";
|
String message = "unable to find watch for record [" + ctx.id() + "]";
|
||||||
|
@ -353,7 +354,8 @@ public class ExecutionService {
|
||||||
|
|
||||||
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, watch.id());
|
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, watch.id());
|
||||||
updateRequest.doc(source);
|
updateRequest.doc(source);
|
||||||
updateRequest.version(watch.version());
|
updateRequest.setIfSeqNo(watch.getSourceSeqNo());
|
||||||
|
updateRequest.setIfPrimaryTerm(watch.getSourcePrimaryTerm());
|
||||||
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN)) {
|
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN)) {
|
||||||
client.update(updateRequest).actionGet(indexDefaultTimeout);
|
client.update(updateRequest).actionGet(indexDefaultTimeout);
|
||||||
} catch (DocumentMissingException e) {
|
} catch (DocumentMissingException e) {
|
||||||
|
|
|
@ -50,8 +50,7 @@ public class RestExecuteWatchAction extends WatcherRestHandler implements RestRe
|
||||||
WatchField.INPUT.getPreferredName(), WatchField.CONDITION.getPreferredName(),
|
WatchField.INPUT.getPreferredName(), WatchField.CONDITION.getPreferredName(),
|
||||||
WatchField.ACTIONS.getPreferredName(), WatchField.TRANSFORM.getPreferredName(),
|
WatchField.ACTIONS.getPreferredName(), WatchField.TRANSFORM.getPreferredName(),
|
||||||
WatchField.THROTTLE_PERIOD.getPreferredName(), WatchField.THROTTLE_PERIOD_HUMAN.getPreferredName(),
|
WatchField.THROTTLE_PERIOD.getPreferredName(), WatchField.THROTTLE_PERIOD_HUMAN.getPreferredName(),
|
||||||
WatchField.METADATA.getPreferredName(), WatchField.STATUS.getPreferredName(),
|
WatchField.METADATA.getPreferredName(), WatchField.STATUS.getPreferredName());
|
||||||
WatchField.VERSION.getPreferredName());
|
|
||||||
|
|
||||||
public RestExecuteWatchAction(Settings settings, RestController controller) {
|
public RestExecuteWatchAction(Settings settings, RestController controller) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.elasticsearch.xpack.watcher.rest.action;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.elasticsearch.common.logging.DeprecationLogger;
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.rest.BytesRestResponse;
|
import org.elasticsearch.rest.BytesRestResponse;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
|
@ -22,7 +21,6 @@ import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchReques
|
||||||
import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse;
|
import org.elasticsearch.xpack.core.watcher.transport.actions.get.GetWatchResponse;
|
||||||
import org.elasticsearch.xpack.watcher.rest.WatcherRestHandler;
|
import org.elasticsearch.xpack.watcher.rest.WatcherRestHandler;
|
||||||
|
|
||||||
|
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||||
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
|
||||||
import static org.elasticsearch.rest.RestStatus.OK;
|
import static org.elasticsearch.rest.RestStatus.OK;
|
||||||
|
@ -50,17 +48,9 @@ public class RestGetWatchAction extends WatcherRestHandler {
|
||||||
return channel -> client.getWatch(getWatchRequest, new RestBuilderListener<GetWatchResponse>(channel) {
|
return channel -> client.getWatch(getWatchRequest, new RestBuilderListener<GetWatchResponse>(channel) {
|
||||||
@Override
|
@Override
|
||||||
public RestResponse buildResponse(GetWatchResponse response, XContentBuilder builder) throws Exception {
|
public RestResponse buildResponse(GetWatchResponse response, XContentBuilder builder) throws Exception {
|
||||||
builder.startObject()
|
builder.startObject();
|
||||||
.field("found", response.isFound())
|
response.toXContent(builder, request);
|
||||||
.field("_id", response.getId());
|
|
||||||
if (response.isFound()) {
|
|
||||||
builder.field("_version", response.getVersion());
|
|
||||||
ToXContent.MapParams xContentParams = new ToXContent.MapParams(request.params());
|
|
||||||
builder.field("status", response.getStatus(), xContentParams);
|
|
||||||
builder.field("watch", response.getSource(), xContentParams);
|
|
||||||
}
|
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
RestStatus status = response.isFound() ? OK : NOT_FOUND;
|
RestStatus status = response.isFound() ? OK : NOT_FOUND;
|
||||||
return new BytesRestResponse(status, builder);
|
return new BytesRestResponse(status, builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,15 +58,13 @@ public class RestPutWatchAction extends WatcherRestHandler implements RestReques
|
||||||
PutWatchRequest putWatchRequest =
|
PutWatchRequest putWatchRequest =
|
||||||
new PutWatchRequest(request.param("id"), request.content(), request.getXContentType());
|
new PutWatchRequest(request.param("id"), request.content(), request.getXContentType());
|
||||||
putWatchRequest.setVersion(request.paramAsLong("version", Versions.MATCH_ANY));
|
putWatchRequest.setVersion(request.paramAsLong("version", Versions.MATCH_ANY));
|
||||||
|
putWatchRequest.setIfSeqNo(request.paramAsLong("if_seq_no", putWatchRequest.getIfSeqNo()));
|
||||||
|
putWatchRequest.setIfPrimaryTerm(request.paramAsLong("if_primary_term", putWatchRequest.getIfPrimaryTerm()));
|
||||||
putWatchRequest.setActive(request.paramAsBoolean("active", putWatchRequest.isActive()));
|
putWatchRequest.setActive(request.paramAsBoolean("active", putWatchRequest.isActive()));
|
||||||
return channel -> client.putWatch(putWatchRequest, new RestBuilderListener<PutWatchResponse>(channel) {
|
return channel -> client.putWatch(putWatchRequest, new RestBuilderListener<PutWatchResponse>(channel) {
|
||||||
@Override
|
@Override
|
||||||
public RestResponse buildResponse(PutWatchResponse response, XContentBuilder builder) throws Exception {
|
public RestResponse buildResponse(PutWatchResponse response, XContentBuilder builder) throws Exception {
|
||||||
builder.startObject()
|
response.toXContent(builder, request);
|
||||||
.field("_id", response.getId())
|
|
||||||
.field("_version", response.getVersion())
|
|
||||||
.field("created", response.isCreated())
|
|
||||||
.endObject();
|
|
||||||
RestStatus status = response.isCreated() ? CREATED : OK;
|
RestStatus status = response.isCreated() ? CREATED : OK;
|
||||||
return new BytesRestResponse(status, builder);
|
return new BytesRestResponse(status, builder);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.xpack.watcher.transport.actions.ack;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchStatusException;
|
import org.elasticsearch.ElasticsearchStatusException;
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
import org.elasticsearch.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import org.elasticsearch.action.get.GetRequest;
|
||||||
import org.elasticsearch.action.get.GetResponse;
|
import org.elasticsearch.action.get.GetResponse;
|
||||||
|
@ -16,6 +17,7 @@ import org.elasticsearch.action.update.UpdateRequest;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.routing.Preference;
|
import org.elasticsearch.cluster.routing.Preference;
|
||||||
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
@ -49,15 +51,17 @@ public class TransportAckWatchAction extends WatcherTransportAction<AckWatchRequ
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final WatchParser parser;
|
private final WatchParser parser;
|
||||||
private final Client client;
|
private final Client client;
|
||||||
|
private final ClusterService clusterService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TransportAckWatchAction(TransportService transportService, ActionFilters actionFilters,
|
public TransportAckWatchAction(TransportService transportService, ActionFilters actionFilters,
|
||||||
Clock clock, XPackLicenseState licenseState, WatchParser parser,
|
Clock clock, XPackLicenseState licenseState, WatchParser parser,
|
||||||
Client client) {
|
Client client, ClusterService clusterService) {
|
||||||
super(AckWatchAction.NAME, transportService, actionFilters, licenseState, AckWatchRequest::new);
|
super(AckWatchAction.NAME, transportService, actionFilters, licenseState, AckWatchRequest::new);
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
this.clusterService = clusterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,8 +86,7 @@ public class TransportAckWatchAction extends WatcherTransportAction<AckWatchRequ
|
||||||
} else {
|
} else {
|
||||||
DateTime now = new DateTime(clock.millis(), UTC);
|
DateTime now = new DateTime(clock.millis(), UTC);
|
||||||
Watch watch = parser.parseWithSecrets(request.getWatchId(), true, getResponse.getSourceAsBytesRef(),
|
Watch watch = parser.parseWithSecrets(request.getWatchId(), true, getResponse.getSourceAsBytesRef(),
|
||||||
now, XContentType.JSON);
|
now, XContentType.JSON, getResponse.getSeqNo(), getResponse.getPrimaryTerm());
|
||||||
watch.version(getResponse.getVersion());
|
|
||||||
watch.status().version(getResponse.getVersion());
|
watch.status().version(getResponse.getVersion());
|
||||||
String[] actionIds = request.getActionIds();
|
String[] actionIds = request.getActionIds();
|
||||||
if (actionIds == null || actionIds.length == 0) {
|
if (actionIds == null || actionIds.length == 0) {
|
||||||
|
@ -99,7 +102,12 @@ public class TransportAckWatchAction extends WatcherTransportAction<AckWatchRequ
|
||||||
|
|
||||||
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, request.getWatchId());
|
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, request.getWatchId());
|
||||||
// this may reject this action, but prevents concurrent updates from a watch execution
|
// this may reject this action, but prevents concurrent updates from a watch execution
|
||||||
|
if (clusterService.state().nodes().getMinNodeVersion().onOrAfter(Version.V_7_0_0)) {
|
||||||
|
updateRequest.setIfSeqNo(getResponse.getSeqNo());
|
||||||
|
updateRequest.setIfPrimaryTerm(getResponse.getPrimaryTerm());
|
||||||
|
} else {
|
||||||
updateRequest.version(getResponse.getVersion());
|
updateRequest.version(getResponse.getVersion());
|
||||||
|
}
|
||||||
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
XContentBuilder builder = jsonBuilder();
|
XContentBuilder builder = jsonBuilder();
|
||||||
builder.startObject()
|
builder.startObject()
|
||||||
|
|
|
@ -79,8 +79,7 @@ public class TransportActivateWatchAction extends WatcherTransportAction<Activat
|
||||||
ActionListener.<GetResponse>wrap(getResponse -> {
|
ActionListener.<GetResponse>wrap(getResponse -> {
|
||||||
if (getResponse.isExists()) {
|
if (getResponse.isExists()) {
|
||||||
Watch watch = parser.parseWithSecrets(request.getWatchId(), true, getResponse.getSourceAsBytesRef(), now,
|
Watch watch = parser.parseWithSecrets(request.getWatchId(), true, getResponse.getSourceAsBytesRef(), now,
|
||||||
XContentType.JSON);
|
XContentType.JSON, getResponse.getSeqNo(), getResponse.getPrimaryTerm());
|
||||||
watch.version(getResponse.getVersion());
|
|
||||||
watch.status().version(getResponse.getVersion());
|
watch.status().version(getResponse.getVersion());
|
||||||
listener.onResponse(new ActivateWatchResponse(watch.status()));
|
listener.onResponse(new ActivateWatchResponse(watch.status()));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.license.XPackLicenseState;
|
import org.elasticsearch.license.XPackLicenseState;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
@ -86,9 +87,8 @@ public class TransportExecuteWatchAction extends WatcherTransportAction<ExecuteW
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, getRequest,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, getRequest,
|
||||||
ActionListener.<GetResponse>wrap(response -> {
|
ActionListener.<GetResponse>wrap(response -> {
|
||||||
if (response.isExists()) {
|
if (response.isExists()) {
|
||||||
Watch watch =
|
Watch watch = watchParser.parse(request.getId(), true, response.getSourceAsBytesRef(),
|
||||||
watchParser.parse(request.getId(), true, response.getSourceAsBytesRef(), request.getXContentType());
|
request.getXContentType(), response.getSeqNo(), response.getPrimaryTerm());
|
||||||
watch.version(response.getVersion());
|
|
||||||
watch.status().version(response.getVersion());
|
watch.status().version(response.getVersion());
|
||||||
executeWatch(request, listener, watch, true);
|
executeWatch(request, listener, watch, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,7 +99,7 @@ public class TransportExecuteWatchAction extends WatcherTransportAction<ExecuteW
|
||||||
try {
|
try {
|
||||||
assert !request.isRecordExecution();
|
assert !request.isRecordExecution();
|
||||||
Watch watch = watchParser.parse(ExecuteWatchRequest.INLINE_WATCH_ID, true, request.getWatchSource(),
|
Watch watch = watchParser.parse(ExecuteWatchRequest.INLINE_WATCH_ID, true, request.getWatchSource(),
|
||||||
request.getXContentType());
|
request.getXContentType(), SequenceNumbers.UNASSIGNED_SEQ_NO, SequenceNumbers.UNASSIGNED_PRIMARY_TERM);
|
||||||
executeWatch(request, listener, watch, false);
|
executeWatch(request, listener, watch, false);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error(new ParameterizedMessage("failed to parse [{}]", request.getId()), e);
|
logger.error(new ParameterizedMessage("failed to parse [{}]", request.getId()), e);
|
||||||
|
|
|
@ -64,15 +64,15 @@ public class TransportGetWatchAction extends WatcherTransportAction<GetWatchRequ
|
||||||
// so that it indicates the the status is managed by watcher itself.
|
// so that it indicates the the status is managed by watcher itself.
|
||||||
DateTime now = new DateTime(clock.millis(), UTC);
|
DateTime now = new DateTime(clock.millis(), UTC);
|
||||||
Watch watch = parser.parseWithSecrets(request.getId(), true, getResponse.getSourceAsBytesRef(), now,
|
Watch watch = parser.parseWithSecrets(request.getId(), true, getResponse.getSourceAsBytesRef(), now,
|
||||||
XContentType.JSON);
|
XContentType.JSON, getResponse.getSeqNo(), getResponse.getPrimaryTerm());
|
||||||
watch.toXContent(builder, WatcherParams.builder()
|
watch.toXContent(builder, WatcherParams.builder()
|
||||||
.hideSecrets(true)
|
.hideSecrets(true)
|
||||||
.includeStatus(false)
|
.includeStatus(false)
|
||||||
.build());
|
.build());
|
||||||
watch.version(getResponse.getVersion());
|
|
||||||
watch.status().version(getResponse.getVersion());
|
watch.status().version(getResponse.getVersion());
|
||||||
listener.onResponse(new GetWatchResponse(watch.id(), getResponse.getVersion(), watch.status(),
|
listener.onResponse(new GetWatchResponse(watch.id(), getResponse.getVersion(),
|
||||||
new XContentSource(BytesReference.bytes(builder), XContentType.JSON)));
|
watch.getSourceSeqNo(), watch.getSourcePrimaryTerm(),
|
||||||
|
watch.status(), new XContentSource(BytesReference.bytes(builder), XContentType.JSON)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
listener.onResponse(new GetWatchResponse(request.getId()));
|
listener.onResponse(new GetWatchResponse(request.getId()));
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.license.XPackLicenseState;
|
import org.elasticsearch.license.XPackLicenseState;
|
||||||
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
|
import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest;
|
||||||
import org.elasticsearch.protocol.xpack.watcher.PutWatchResponse;
|
import org.elasticsearch.protocol.xpack.watcher.PutWatchResponse;
|
||||||
|
@ -77,8 +78,9 @@ public class TransportPutWatchAction extends WatcherTransportAction<PutWatchRequ
|
||||||
protected void doExecute(PutWatchRequest request, ActionListener<PutWatchResponse> listener) {
|
protected void doExecute(PutWatchRequest request, ActionListener<PutWatchResponse> listener) {
|
||||||
try {
|
try {
|
||||||
DateTime now = new DateTime(clock.millis(), UTC);
|
DateTime now = new DateTime(clock.millis(), UTC);
|
||||||
boolean isUpdate = request.getVersion() > 0;
|
boolean isUpdate = request.getVersion() > 0 || request.getIfSeqNo() != SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
Watch watch = parser.parseWithSecrets(request.getId(), false, request.getSource(), now, request.xContentType(), isUpdate);
|
Watch watch = parser.parseWithSecrets(request.getId(), false, request.getSource(), now, request.xContentType(),
|
||||||
|
isUpdate, request.getIfSeqNo(), request.getIfPrimaryTerm());
|
||||||
watch.setState(request.isActive(), now);
|
watch.setState(request.isActive(), now);
|
||||||
|
|
||||||
// ensure we only filter for the allowed headers
|
// ensure we only filter for the allowed headers
|
||||||
|
@ -92,14 +94,20 @@ public class TransportPutWatchAction extends WatcherTransportAction<PutWatchRequ
|
||||||
|
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, request.getId());
|
UpdateRequest updateRequest = new UpdateRequest(Watch.INDEX, Watch.DOC_TYPE, request.getId());
|
||||||
|
if (request.getIfSeqNo() != SequenceNumbers.UNASSIGNED_SEQ_NO) {
|
||||||
|
updateRequest.setIfSeqNo(request.getIfSeqNo());
|
||||||
|
updateRequest.setIfPrimaryTerm(request.getIfPrimaryTerm());
|
||||||
|
} else {
|
||||||
updateRequest.version(request.getVersion());
|
updateRequest.version(request.getVersion());
|
||||||
|
}
|
||||||
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
updateRequest.doc(builder);
|
updateRequest.doc(builder);
|
||||||
|
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, updateRequest,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, updateRequest,
|
||||||
ActionListener.<UpdateResponse>wrap(response -> {
|
ActionListener.<UpdateResponse>wrap(response -> {
|
||||||
boolean created = response.getResult() == DocWriteResponse.Result.CREATED;
|
boolean created = response.getResult() == DocWriteResponse.Result.CREATED;
|
||||||
listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(), created));
|
listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(),
|
||||||
|
response.getSeqNo(), response.getPrimaryTerm(), created));
|
||||||
}, listener::onFailure),
|
}, listener::onFailure),
|
||||||
client::update);
|
client::update);
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,7 +117,8 @@ public class TransportPutWatchAction extends WatcherTransportAction<PutWatchRequ
|
||||||
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, indexRequest,
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), WATCHER_ORIGIN, indexRequest,
|
||||||
ActionListener.<IndexResponse>wrap(response -> {
|
ActionListener.<IndexResponse>wrap(response -> {
|
||||||
boolean created = response.getResult() == DocWriteResponse.Result.CREATED;
|
boolean created = response.getResult() == DocWriteResponse.Result.CREATED;
|
||||||
listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(), created));
|
listener.onResponse(new PutWatchResponse(response.getId(), response.getVersion(),
|
||||||
|
response.getSeqNo(), response.getPrimaryTerm(), created));
|
||||||
}, listener::onFailure),
|
}, listener::onFailure),
|
||||||
client::index);
|
client::index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import org.apache.logging.log4j.Logger;
|
||||||
import org.elasticsearch.ElasticsearchParseException;
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
|
||||||
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
|
@ -74,13 +73,15 @@ public class WatchParser {
|
||||||
this.defaultActions = Collections.emptyList();
|
this.defaultActions = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Watch parse(String name, boolean includeStatus, BytesReference source, XContentType xContentType) throws IOException {
|
public Watch parse(String name, boolean includeStatus, BytesReference source, XContentType xContentType,
|
||||||
return parse(name, includeStatus, false, source, new DateTime(clock.millis(), UTC), xContentType, false);
|
long sourceSeqNo, long sourcePrimaryTerm) throws IOException {
|
||||||
|
return parse(name, includeStatus, false, source, new DateTime(clock.millis(), UTC), xContentType, false,
|
||||||
|
sourceSeqNo, sourcePrimaryTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Watch parse(String name, boolean includeStatus, BytesReference source, DateTime now,
|
public Watch parse(String name, boolean includeStatus, BytesReference source, DateTime now,
|
||||||
XContentType xContentType) throws IOException {
|
XContentType xContentType, long sourceSeqNo, long sourcePrimaryTerm) throws IOException {
|
||||||
return parse(name, includeStatus, false, source, now, xContentType, false);
|
return parse(name, includeStatus, false, source, now, xContentType, false, sourceSeqNo, sourcePrimaryTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -95,17 +96,20 @@ public class WatchParser {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now,
|
public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now,
|
||||||
XContentType xContentType, boolean allowRedactedPasswords) throws IOException {
|
XContentType xContentType, boolean allowRedactedPasswords, long sourceSeqNo, long sourcePrimaryTerm
|
||||||
return parse(id, includeStatus, true, source, now, xContentType, allowRedactedPasswords);
|
) throws IOException {
|
||||||
|
return parse(id, includeStatus, true, source, now, xContentType, allowRedactedPasswords, sourceSeqNo, sourcePrimaryTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now,
|
public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now,
|
||||||
XContentType xContentType) throws IOException {
|
XContentType xContentType, long sourceSeqNo, long sourcePrimaryTerm) throws IOException {
|
||||||
return parse(id, includeStatus, true, source, now, xContentType, false);
|
return parse(id, includeStatus, true, source, now, xContentType, false, sourceSeqNo, sourcePrimaryTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Watch parse(String id, boolean includeStatus, boolean withSecrets, BytesReference source, DateTime now,
|
private Watch parse(String id, boolean includeStatus, boolean withSecrets, BytesReference source, DateTime now,
|
||||||
XContentType xContentType, boolean allowRedactedPasswords) throws IOException {
|
XContentType xContentType, boolean allowRedactedPasswords, long sourceSeqNo, long sourcePrimaryTerm)
|
||||||
|
throws IOException {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("parsing watch [{}] ", source.utf8ToString());
|
logger.trace("parsing watch [{}] ", source.utf8ToString());
|
||||||
}
|
}
|
||||||
|
@ -115,13 +119,14 @@ public class WatchParser {
|
||||||
LoggingDeprecationHandler.INSTANCE, stream),
|
LoggingDeprecationHandler.INSTANCE, stream),
|
||||||
now, withSecrets ? cryptoService : null, allowRedactedPasswords)) {
|
now, withSecrets ? cryptoService : null, allowRedactedPasswords)) {
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
return parse(id, includeStatus, parser);
|
return parse(id, includeStatus, parser, sourceSeqNo, sourcePrimaryTerm);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw ioException("could not parse watch [{}]", ioe, id);
|
throw ioException("could not parse watch [{}]", ioe, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Watch parse(String id, boolean includeStatus, WatcherXContentParser parser) throws IOException {
|
public Watch parse(String id, boolean includeStatus, WatcherXContentParser parser, long sourceSeqNo, long sourcePrimaryTerm)
|
||||||
|
throws IOException {
|
||||||
Trigger trigger = null;
|
Trigger trigger = null;
|
||||||
ExecutableInput input = defaultInput;
|
ExecutableInput input = defaultInput;
|
||||||
ExecutableCondition condition = defaultCondition;
|
ExecutableCondition condition = defaultCondition;
|
||||||
|
@ -130,7 +135,6 @@ public class WatchParser {
|
||||||
TimeValue throttlePeriod = null;
|
TimeValue throttlePeriod = null;
|
||||||
Map<String, Object> metatdata = null;
|
Map<String, Object> metatdata = null;
|
||||||
WatchStatus status = null;
|
WatchStatus status = null;
|
||||||
long version = Versions.MATCH_ANY;
|
|
||||||
|
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
|
@ -163,8 +167,6 @@ public class WatchParser {
|
||||||
actions = actionRegistry.parseActions(id, parser);
|
actions = actionRegistry.parseActions(id, parser);
|
||||||
} else if (WatchField.METADATA.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (WatchField.METADATA.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
metatdata = parser.map();
|
metatdata = parser.map();
|
||||||
} else if (WatchField.VERSION.match(currentFieldName, parser.getDeprecationHandler())) {
|
|
||||||
version = parser.longValue();
|
|
||||||
} else if (WatchField.STATUS.match(currentFieldName, parser.getDeprecationHandler())) {
|
} else if (WatchField.STATUS.match(currentFieldName, parser.getDeprecationHandler())) {
|
||||||
if (includeStatus) {
|
if (includeStatus) {
|
||||||
status = WatchStatus.parse(id, parser);
|
status = WatchStatus.parse(id, parser);
|
||||||
|
@ -198,6 +200,7 @@ public class WatchParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return new Watch(id, trigger, input, condition, transform, throttlePeriod, actions, metatdata, status, version);
|
return new Watch(
|
||||||
|
id, trigger, input, condition, transform, throttlePeriod, actions, metatdata, status, sourceSeqNo, sourcePrimaryTerm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
import static org.joda.time.DateTimeZone.UTC;
|
import static org.joda.time.DateTimeZone.UTC;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -134,13 +135,13 @@ public class WatcherIndexingListenerTests extends ESTestCase {
|
||||||
boolean watchActive = randomBoolean();
|
boolean watchActive = randomBoolean();
|
||||||
boolean isNewWatch = randomBoolean();
|
boolean isNewWatch = randomBoolean();
|
||||||
Watch watch = mockWatch("_id", watchActive, isNewWatch);
|
Watch watch = mockWatch("_id", watchActive, isNewWatch);
|
||||||
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject())).thenReturn(watch);
|
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
Engine.Index returnedOperation = listener.preIndex(shardId, operation);
|
Engine.Index returnedOperation = listener.preIndex(shardId, operation);
|
||||||
assertThat(returnedOperation, is(operation));
|
assertThat(returnedOperation, is(operation));
|
||||||
|
|
||||||
DateTime now = new DateTime(clock.millis(), UTC);
|
DateTime now = new DateTime(clock.millis(), UTC);
|
||||||
verify(parser).parseWithSecrets(eq(operation.id()), eq(true), eq(BytesArray.EMPTY), eq(now), anyObject());
|
verify(parser).parseWithSecrets(eq(operation.id()), eq(true), eq(BytesArray.EMPTY), eq(now), anyObject(), anyLong(), anyLong());
|
||||||
|
|
||||||
if (isNewWatch) {
|
if (isNewWatch) {
|
||||||
if (watchActive) {
|
if (watchActive) {
|
||||||
|
@ -162,7 +163,7 @@ public class WatcherIndexingListenerTests extends ESTestCase {
|
||||||
|
|
||||||
when(shardId.getIndexName()).thenReturn(Watch.INDEX);
|
when(shardId.getIndexName()).thenReturn(Watch.INDEX);
|
||||||
when(operation.type()).thenReturn(Watch.DOC_TYPE);
|
when(operation.type()).thenReturn(Watch.DOC_TYPE);
|
||||||
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject())).thenReturn(watch);
|
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
for (int idx = 0; idx < totalShardCount; idx++) {
|
for (int idx = 0; idx < totalShardCount; idx++) {
|
||||||
final Map<ShardId, ShardAllocationConfiguration> localShards = new HashMap<>();
|
final Map<ShardId, ShardAllocationConfiguration> localShards = new HashMap<>();
|
||||||
|
@ -207,7 +208,7 @@ public class WatcherIndexingListenerTests extends ESTestCase {
|
||||||
when(operation.id()).thenReturn(id);
|
when(operation.id()).thenReturn(id);
|
||||||
when(operation.source()).thenReturn(BytesArray.EMPTY);
|
when(operation.source()).thenReturn(BytesArray.EMPTY);
|
||||||
when(shardId.getIndexName()).thenReturn(Watch.INDEX);
|
when(shardId.getIndexName()).thenReturn(Watch.INDEX);
|
||||||
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject()))
|
when(parser.parseWithSecrets(anyObject(), eq(true), anyObject(), anyObject(), anyObject(), anyLong(), anyLong()))
|
||||||
.thenThrow(new IOException("self thrown"));
|
.thenThrow(new IOException("self thrown"));
|
||||||
|
|
||||||
ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class,
|
ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class,
|
||||||
|
|
|
@ -70,6 +70,7 @@ import static java.util.Arrays.asList;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -194,7 +195,7 @@ public class WatcherServiceTests extends ESTestCase {
|
||||||
Watch watch = mock(Watch.class);
|
Watch watch = mock(Watch.class);
|
||||||
when(watchStatus.state()).thenReturn(state);
|
when(watchStatus.state()).thenReturn(state);
|
||||||
when(watch.status()).thenReturn(watchStatus);
|
when(watch.status()).thenReturn(watchStatus);
|
||||||
when(parser.parse(eq(id), eq(true), any(), eq(XContentType.JSON))).thenReturn(watch);
|
when(parser.parse(eq(id), eq(true), any(), eq(XContentType.JSON), anyLong(), anyLong())).thenReturn(watch);
|
||||||
}
|
}
|
||||||
SearchHits searchHits = new SearchHits(hits, new TotalHits(count, TotalHits.Relation.EQUAL_TO), 1.0f);
|
SearchHits searchHits = new SearchHits(hits, new TotalHits(count, TotalHits.Relation.EQUAL_TO), 1.0f);
|
||||||
SearchResponseSections sections = new SearchResponseSections(searchHits, null, null, false, false, null, 1);
|
SearchResponseSections sections = new SearchResponseSections(searchHits, null, null, false, false, null, 1);
|
||||||
|
|
|
@ -101,6 +101,7 @@ import static org.hamcrest.Matchers.sameInstance;
|
||||||
import static org.joda.time.DateTime.now;
|
import static org.joda.time.DateTime.now;
|
||||||
import static org.joda.time.DateTimeZone.UTC;
|
import static org.joda.time.DateTimeZone.UTC;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doThrow;
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
@ -166,7 +167,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
DateTime now = new DateTime(clock.millis());
|
DateTime now = new DateTime(clock.millis());
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
||||||
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
Condition.Result conditionResult = InternalAlwaysCondition.RESULT_INSTANCE;
|
Condition.Result conditionResult = InternalAlwaysCondition.RESULT_INSTANCE;
|
||||||
ExecutableCondition condition = mock(ExecutableCondition.class);
|
ExecutableCondition condition = mock(ExecutableCondition.class);
|
||||||
|
@ -270,7 +271,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
DateTime now = new DateTime(clock.millis());
|
DateTime now = new DateTime(clock.millis());
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
||||||
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
input = mock(ExecutableInput.class);
|
input = mock(ExecutableInput.class);
|
||||||
Input.Result inputResult = mock(Input.Result.class);
|
Input.Result inputResult = mock(Input.Result.class);
|
||||||
|
@ -339,7 +340,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
DateTime now = new DateTime(clock.millis());
|
DateTime now = new DateTime(clock.millis());
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
||||||
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
ExecutableCondition condition = mock(ExecutableCondition.class);
|
ExecutableCondition condition = mock(ExecutableCondition.class);
|
||||||
Condition.Result conditionResult = mock(Condition.Result.class);
|
Condition.Result conditionResult = mock(Condition.Result.class);
|
||||||
|
@ -404,7 +405,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
DateTime now = new DateTime(clock.millis());
|
DateTime now = new DateTime(clock.millis());
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
||||||
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(), now, event, timeValueSeconds(5));
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
Condition.Result conditionResult = InternalAlwaysCondition.RESULT_INSTANCE;
|
Condition.Result conditionResult = InternalAlwaysCondition.RESULT_INSTANCE;
|
||||||
ExecutableCondition condition = mock(ExecutableCondition.class);
|
ExecutableCondition condition = mock(ExecutableCondition.class);
|
||||||
|
@ -464,7 +465,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
GetResponse getResponse = mock(GetResponse.class);
|
GetResponse getResponse = mock(GetResponse.class);
|
||||||
when(getResponse.isExists()).thenReturn(true);
|
when(getResponse.isExists()).thenReturn(true);
|
||||||
mockGetWatchResponse(client, "_id", getResponse);
|
mockGetWatchResponse(client, "_id", getResponse);
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
DateTime now = new DateTime(clock.millis());
|
DateTime now = new DateTime(clock.millis());
|
||||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_id", now, now);
|
||||||
|
@ -838,7 +839,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
when(getResponse.isExists()).thenReturn(true);
|
when(getResponse.isExists()).thenReturn(true);
|
||||||
when(getResponse.getId()).thenReturn("foo");
|
when(getResponse.getId()).thenReturn("foo");
|
||||||
mockGetWatchResponse(client, "foo", getResponse);
|
mockGetWatchResponse(client, "foo", getResponse);
|
||||||
when(parser.parseWithSecrets(eq("foo"), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq("foo"), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
// execute needs to fail as well as storing the history
|
// execute needs to fail as well as storing the history
|
||||||
doThrow(new EsRejectedExecutionException()).when(executor).execute(any());
|
doThrow(new EsRejectedExecutionException()).when(executor).execute(any());
|
||||||
|
@ -971,7 +972,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
GetResponse getResponse = mock(GetResponse.class);
|
GetResponse getResponse = mock(GetResponse.class);
|
||||||
when(getResponse.isExists()).thenReturn(true);
|
when(getResponse.isExists()).thenReturn(true);
|
||||||
mockGetWatchResponse(client, "_id", getResponse);
|
mockGetWatchResponse(client, "_id", getResponse);
|
||||||
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq(watch.id()), eq(true), any(), any(), any(), anyLong(), anyLong())).thenReturn(watch);
|
||||||
|
|
||||||
WatchRecord.MessageWatchRecord record = mock(WatchRecord.MessageWatchRecord.class);
|
WatchRecord.MessageWatchRecord record = mock(WatchRecord.MessageWatchRecord.class);
|
||||||
when(record.state()).thenReturn(ExecutionState.EXECUTION_NOT_NEEDED);
|
when(record.state()).thenReturn(ExecutionState.EXECUTION_NOT_NEEDED);
|
||||||
|
@ -1017,7 +1018,7 @@ public class ExecutionServiceTests extends ESTestCase {
|
||||||
public void testUpdateWatchStatusDoesNotUpdateState() throws Exception {
|
public void testUpdateWatchStatusDoesNotUpdateState() throws Exception {
|
||||||
WatchStatus status = new WatchStatus(DateTime.now(UTC), Collections.emptyMap());
|
WatchStatus status = new WatchStatus(DateTime.now(UTC), Collections.emptyMap());
|
||||||
Watch watch = new Watch("_id", new ManualTrigger(), new ExecutableNoneInput(), InternalAlwaysCondition.INSTANCE, null, null,
|
Watch watch = new Watch("_id", new ManualTrigger(), new ExecutableNoneInput(), InternalAlwaysCondition.INSTANCE, null, null,
|
||||||
Collections.emptyList(), null, status, 1L);
|
Collections.emptyList(), null, status, 1L, 1L);
|
||||||
|
|
||||||
final AtomicBoolean assertionsTriggered = new AtomicBoolean(false);
|
final AtomicBoolean assertionsTriggered = new AtomicBoolean(false);
|
||||||
doAnswer(invocation -> {
|
doAnswer(invocation -> {
|
||||||
|
|
|
@ -55,7 +55,6 @@ import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import javax.mail.internet.AddressException;
|
import javax.mail.internet.AddressException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -134,7 +133,7 @@ public final class WatcherTestUtils {
|
||||||
null,
|
null,
|
||||||
new ArrayList<>(),
|
new ArrayList<>(),
|
||||||
null,
|
null,
|
||||||
new WatchStatus(new DateTime(0, UTC), emptyMap()), 1L);
|
new WatchStatus(new DateTime(0, UTC), emptyMap()), 1L, 1L);
|
||||||
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(),
|
TriggeredExecutionContext context = new TriggeredExecutionContext(watch.id(),
|
||||||
new DateTime(0, UTC),
|
new DateTime(0, UTC),
|
||||||
new ScheduleTriggerEvent(watch.id(), new DateTime(0, UTC), new DateTime(0, UTC)),
|
new ScheduleTriggerEvent(watch.id(), new DateTime(0, UTC), new DateTime(0, UTC)),
|
||||||
|
@ -181,7 +180,7 @@ public final class WatcherTestUtils {
|
||||||
new TimeValue(0),
|
new TimeValue(0),
|
||||||
actions,
|
actions,
|
||||||
Collections.singletonMap("foo", "bar"),
|
Collections.singletonMap("foo", "bar"),
|
||||||
new WatchStatus(now, statuses), 1L);
|
new WatchStatus(now, statuses), 1L, 1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SearchType getRandomSupportedSearchType() {
|
public static SearchType getRandomSupportedSearchType() {
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class ScheduleEngineTriggerBenchmark {
|
||||||
List<Watch> watches = new ArrayList<>(numWatches);
|
List<Watch> watches = new ArrayList<>(numWatches);
|
||||||
for (int i = 0; i < numWatches; i++) {
|
for (int i = 0; i < numWatches; i++) {
|
||||||
watches.add(new Watch("job_" + i, new ScheduleTrigger(interval(interval + "s")), new ExecutableNoneInput(),
|
watches.add(new Watch("job_" + i, new ScheduleTrigger(interval(interval + "s")), new ExecutableNoneInput(),
|
||||||
InternalAlwaysCondition.INSTANCE, null, null, Collections.emptyList(), null, null, 1L));
|
InternalAlwaysCondition.INSTANCE, null, null, Collections.emptyList(), null, null, 1L, 1L));
|
||||||
}
|
}
|
||||||
ScheduleRegistry scheduleRegistry = new ScheduleRegistry(emptySet());
|
ScheduleRegistry scheduleRegistry = new ScheduleRegistry(emptySet());
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,8 @@ public class WatchAckTests extends AbstractWatcherIntegrationTestCase {
|
||||||
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id").get();
|
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id").get();
|
||||||
assertThat(getWatchResponse.isFound(), is(true));
|
assertThat(getWatchResponse.isFound(), is(true));
|
||||||
|
|
||||||
Watch parsedWatch = watchParser().parse(getWatchResponse.getId(), true, getWatchResponse.getSource().getBytes(), XContentType.JSON);
|
Watch parsedWatch = watchParser().parse(getWatchResponse.getId(), true, getWatchResponse.getSource().getBytes(),
|
||||||
|
XContentType.JSON, getWatchResponse.getSeqNo(), getWatchResponse.getPrimaryTerm());
|
||||||
assertThat(parsedWatch.status().actionStatus("_a1").ackStatus().state(),
|
assertThat(parsedWatch.status().actionStatus("_a1").ackStatus().state(),
|
||||||
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
|
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
|
||||||
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
|
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
|
||||||
|
@ -178,7 +179,8 @@ public class WatchAckTests extends AbstractWatcherIntegrationTestCase {
|
||||||
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id").get();
|
GetWatchResponse getWatchResponse = watcherClient().prepareGetWatch("_id").get();
|
||||||
assertThat(getWatchResponse.isFound(), is(true));
|
assertThat(getWatchResponse.isFound(), is(true));
|
||||||
|
|
||||||
Watch parsedWatch = watchParser().parse(getWatchResponse.getId(), true, getWatchResponse.getSource().getBytes(), XContentType.JSON);
|
Watch parsedWatch = watchParser().parse(getWatchResponse.getId(), true,
|
||||||
|
getWatchResponse.getSource().getBytes(), XContentType.JSON, getWatchResponse.getSeqNo(), getWatchResponse.getPrimaryTerm());
|
||||||
assertThat(parsedWatch.status().actionStatus("_a1").ackStatus().state(),
|
assertThat(parsedWatch.status().actionStatus("_a1").ackStatus().state(),
|
||||||
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
|
is(ActionStatus.AckStatus.State.AWAITS_SUCCESSFUL_EXECUTION));
|
||||||
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
|
assertThat(parsedWatch.status().actionStatus("_a2").ackStatus().state(),
|
||||||
|
@ -220,7 +222,8 @@ public class WatchAckTests extends AbstractWatcherIntegrationTestCase {
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
GetResponse getResponse = client().get(new GetRequest(Watch.INDEX, Watch.DOC_TYPE, "_name")).actionGet();
|
GetResponse getResponse = client().get(new GetRequest(Watch.INDEX, Watch.DOC_TYPE, "_name")).actionGet();
|
||||||
Watch indexedWatch = watchParser().parse("_name", true, getResponse.getSourceAsBytesRef(), XContentType.JSON);
|
Watch indexedWatch = watchParser().parse("_name", true, getResponse.getSourceAsBytesRef(), XContentType.JSON,
|
||||||
|
getResponse.getSeqNo(), getResponse.getPrimaryTerm());
|
||||||
assertThat(watchResponse.getStatus().actionStatus("_id").ackStatus().state(),
|
assertThat(watchResponse.getStatus().actionStatus("_id").ackStatus().state(),
|
||||||
equalTo(indexedWatch.status().actionStatus("_id").ackStatus().state()));
|
equalTo(indexedWatch.status().actionStatus("_id").ackStatus().state()));
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ import java.util.Collections;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
|
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
|
||||||
|
import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
|
@ -61,7 +62,7 @@ public class TransportAckWatchActionTests extends ESTestCase {
|
||||||
client = mock(Client.class);
|
client = mock(Client.class);
|
||||||
when(client.threadPool()).thenReturn(threadPool);
|
when(client.threadPool()).thenReturn(threadPool);
|
||||||
action = new TransportAckWatchAction(transportService, new ActionFilters(Collections.emptySet()),
|
action = new TransportAckWatchAction(transportService, new ActionFilters(Collections.emptySet()),
|
||||||
Clock.systemUTC(), new XPackLicenseState(Settings.EMPTY), watchParser, client);
|
Clock.systemUTC(), new XPackLicenseState(Settings.EMPTY), watchParser, client, createClusterService(threadPool));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWatchNotFound() {
|
public void testWatchNotFound() {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyBoolean;
|
import static org.mockito.Matchers.anyBoolean;
|
||||||
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.anyObject;
|
import static org.mockito.Matchers.anyObject;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
@ -57,7 +58,8 @@ public class TransportPutWatchActionTests extends ESTestCase {
|
||||||
TransportService transportService = mock(TransportService.class);
|
TransportService transportService = mock(TransportService.class);
|
||||||
|
|
||||||
WatchParser parser = mock(WatchParser.class);
|
WatchParser parser = mock(WatchParser.class);
|
||||||
when(parser.parseWithSecrets(eq("_id"), eq(false), anyObject(), anyObject(), anyObject(), anyBoolean())).thenReturn(watch);
|
when(parser.parseWithSecrets(eq("_id"), eq(false), anyObject(), anyObject(), anyObject(), anyBoolean(), anyLong(), anyLong()))
|
||||||
|
.thenReturn(watch);
|
||||||
|
|
||||||
Client client = mock(Client.class);
|
Client client = mock(Client.class);
|
||||||
when(client.threadPool()).thenReturn(threadPool);
|
when(client.threadPool()).thenReturn(threadPool);
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.watcher.trigger.schedule.engine;
|
package org.elasticsearch.xpack.watcher.trigger.schedule.engine;
|
||||||
|
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.index.seqno.SequenceNumbers;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
|
import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
|
||||||
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
|
import org.elasticsearch.xpack.core.watcher.watch.ClockMock;
|
||||||
|
@ -273,6 +273,6 @@ public class TickerScheduleEngineTests extends ESTestCase {
|
||||||
private Watch createWatch(String name, Schedule schedule) {
|
private Watch createWatch(String name, Schedule schedule) {
|
||||||
return new Watch(name, new ScheduleTrigger(schedule), new ExecutableNoneInput(),
|
return new Watch(name, new ScheduleTrigger(schedule), new ExecutableNoneInput(),
|
||||||
InternalAlwaysCondition.INSTANCE, null, null,
|
InternalAlwaysCondition.INSTANCE, null, null,
|
||||||
Collections.emptyList(), null, null, Versions.MATCH_ANY);
|
Collections.emptyList(), null, null, SequenceNumbers.UNASSIGNED_SEQ_NO, SequenceNumbers.UNASSIGNED_PRIMARY_TERM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,13 +208,16 @@ public class WatchTests extends ESTestCase {
|
||||||
|
|
||||||
TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10000));
|
TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10000));
|
||||||
|
|
||||||
Watch watch = new Watch("_name", trigger, input, condition, transform, throttlePeriod, actions, metadata, watchStatus, 1L);
|
final long sourceSeqNo = randomNonNegativeLong();
|
||||||
|
final long sourcePrimaryTerm = randomLongBetween(1, 200);
|
||||||
|
Watch watch = new Watch("_name", trigger, input, condition, transform, throttlePeriod, actions, metadata, watchStatus,
|
||||||
|
sourceSeqNo, sourcePrimaryTerm);
|
||||||
|
|
||||||
BytesReference bytes = BytesReference.bytes(jsonBuilder().value(watch));
|
BytesReference bytes = BytesReference.bytes(jsonBuilder().value(watch));
|
||||||
logger.info("{}", bytes.utf8ToString());
|
logger.info("{}", bytes.utf8ToString());
|
||||||
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
||||||
|
|
||||||
Watch parsedWatch = watchParser.parse("_name", includeStatus, bytes, XContentType.JSON);
|
Watch parsedWatch = watchParser.parse("_name", includeStatus, bytes, XContentType.JSON, sourceSeqNo, sourcePrimaryTerm);
|
||||||
|
|
||||||
if (includeStatus) {
|
if (includeStatus) {
|
||||||
assertThat(parsedWatch.status(), equalTo(watchStatus));
|
assertThat(parsedWatch.status(), equalTo(watchStatus));
|
||||||
|
@ -227,6 +230,8 @@ public class WatchTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
assertThat(parsedWatch.metadata(), equalTo(metadata));
|
assertThat(parsedWatch.metadata(), equalTo(metadata));
|
||||||
assertThat(parsedWatch.actions(), equalTo(actions));
|
assertThat(parsedWatch.actions(), equalTo(actions));
|
||||||
|
assertThat(parsedWatch.getSourceSeqNo(), equalTo(sourceSeqNo));
|
||||||
|
assertThat(parsedWatch.getSourcePrimaryTerm(), equalTo(sourcePrimaryTerm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testThatBothStatusFieldsCanBeRead() throws Exception {
|
public void testThatBothStatusFieldsCanBeRead() throws Exception {
|
||||||
|
@ -256,7 +261,7 @@ public class WatchTests extends ESTestCase {
|
||||||
|
|
||||||
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
||||||
XContentBuilder builder = jsonBuilder().startObject().startObject("trigger").endObject().field("status", watchStatus).endObject();
|
XContentBuilder builder = jsonBuilder().startObject().startObject("trigger").endObject().field("status", watchStatus).endObject();
|
||||||
Watch watch = watchParser.parse("foo", true, BytesReference.bytes(builder), XContentType.JSON);
|
Watch watch = watchParser.parse("foo", true, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L);
|
||||||
assertThat(watch.status().state().getTimestamp().getMillis(), is(clock.millis()));
|
assertThat(watch.status().state().getTimestamp().getMillis(), is(clock.millis()));
|
||||||
for (ActionWrapper action : actions) {
|
for (ActionWrapper action : actions) {
|
||||||
assertThat(watch.status().actionStatus(action.id()), is(actionsStatuses.get(action.id())));
|
assertThat(watch.status().actionStatus(action.id()), is(actionsStatuses.get(action.id())));
|
||||||
|
@ -284,7 +289,7 @@ public class WatchTests extends ESTestCase {
|
||||||
.endObject();
|
.endObject();
|
||||||
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, clock);
|
||||||
try {
|
try {
|
||||||
watchParser.parse("failure", false, BytesReference.bytes(jsonBuilder), XContentType.JSON);
|
watchParser.parse("failure", false, BytesReference.bytes(jsonBuilder), XContentType.JSON, 1L, 1L);
|
||||||
fail("This watch should fail to parse as actions is an array");
|
fail("This watch should fail to parse as actions is an array");
|
||||||
} catch (ElasticsearchParseException pe) {
|
} catch (ElasticsearchParseException pe) {
|
||||||
assertThat(pe.getMessage().contains("could not parse actions for watch [failure]"), is(true));
|
assertThat(pe.getMessage().contains("could not parse actions for watch [failure]"), is(true));
|
||||||
|
@ -309,7 +314,7 @@ public class WatchTests extends ESTestCase {
|
||||||
.endObject();
|
.endObject();
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, Clock.systemUTC());
|
WatchParser watchParser = new WatchParser(triggerService, actionRegistry, inputRegistry, null, Clock.systemUTC());
|
||||||
Watch watch = watchParser.parse("failure", false, BytesReference.bytes(builder), XContentType.JSON);
|
Watch watch = watchParser.parse("failure", false, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L);
|
||||||
assertThat(watch, notNullValue());
|
assertThat(watch, notNullValue());
|
||||||
assertThat(watch.trigger(), instanceOf(ScheduleTrigger.class));
|
assertThat(watch.trigger(), instanceOf(ScheduleTrigger.class));
|
||||||
assertThat(watch.input(), instanceOf(ExecutableNoneInput.class));
|
assertThat(watch.input(), instanceOf(ExecutableNoneInput.class));
|
||||||
|
@ -375,7 +380,7 @@ public class WatchTests extends ESTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
// parse in default mode:
|
// parse in default mode:
|
||||||
Watch watch = watchParser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON);
|
Watch watch = watchParser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L);
|
||||||
assertThat(((ScriptCondition) watch.condition()).getScript().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG));
|
assertThat(((ScriptCondition) watch.condition()).getScript().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG));
|
||||||
WatcherSearchTemplateRequest request = ((SearchInput) watch.input().input()).getRequest();
|
WatcherSearchTemplateRequest request = ((SearchInput) watch.input().input()).getRequest();
|
||||||
SearchRequest searchRequest = searchTemplateService.toSearchRequest(request);
|
SearchRequest searchRequest = searchTemplateService.toSearchRequest(request);
|
||||||
|
@ -394,7 +399,7 @@ public class WatchTests extends ESTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
WatchParser parser = createWatchparser();
|
WatchParser parser = createWatchparser();
|
||||||
Watch watch = parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON);
|
Watch watch = parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L);
|
||||||
assertThat(watch, is(notNullValue()));
|
assertThat(watch, is(notNullValue()));
|
||||||
assertThat(watch.input().type(), is(NoneInput.TYPE));
|
assertThat(watch.input().type(), is(NoneInput.TYPE));
|
||||||
}
|
}
|
||||||
|
@ -410,7 +415,7 @@ public class WatchTests extends ESTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
WatchParser parser = createWatchparser();
|
WatchParser parser = createWatchparser();
|
||||||
Watch watch = parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON);
|
Watch watch = parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L);
|
||||||
assertThat(watch, is(notNullValue()));
|
assertThat(watch, is(notNullValue()));
|
||||||
assertThat(watch.actions(), hasSize(0));
|
assertThat(watch.actions(), hasSize(0));
|
||||||
}
|
}
|
||||||
|
@ -429,7 +434,7 @@ public class WatchTests extends ESTestCase {
|
||||||
|
|
||||||
WatchParser parser = createWatchparser();
|
WatchParser parser = createWatchparser();
|
||||||
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
|
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
|
||||||
() -> parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON));
|
() -> parser.parse("_id", false, BytesReference.bytes(builder), XContentType.JSON, 1L, 1L));
|
||||||
assertThat(e.getMessage(), is("could not parse watch [_id]. missing required field [trigger]"));
|
assertThat(e.getMessage(), is("could not parse watch [_id]. missing required field [trigger]"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue