Skip to content

Commit a9cc0e1

Browse files
authored
[ML][Data Frame] Add optional defer_validation param to PUT (#44455)
* [ML][Data Frame] Add optional defer_validation param to PUT * addressing PR comments * reverting bad replace * addressing pr comments * Update put-transform.asciidoc * Update put-transform.asciidoc * Update put-transform.asciidoc
1 parent 73f8f1f commit a9cc0e1

File tree

20 files changed

+316
-117
lines changed

20 files changed

+316
-117
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/DataFrameRequestConverters.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import static org.elasticsearch.client.RequestConverters.createEntity;
4040
import static org.elasticsearch.client.dataframe.DeleteDataFrameTransformRequest.FORCE;
4141
import static org.elasticsearch.client.dataframe.GetDataFrameTransformRequest.ALLOW_NO_MATCH;
42+
import static org.elasticsearch.client.dataframe.PutDataFrameTransformRequest.DEFER_VALIDATION;
4243

4344
final class DataFrameRequestConverters {
4445

@@ -51,6 +52,9 @@ static Request putDataFrameTransform(PutDataFrameTransformRequest putRequest) th
5152
.build();
5253
Request request = new Request(HttpPut.METHOD_NAME, endpoint);
5354
request.setEntity(createEntity(putRequest, REQUEST_BODY_CONTENT_TYPE));
55+
if (putRequest.getDeferValidation() != null) {
56+
request.addParameter(DEFER_VALIDATION, Boolean.toString(putRequest.getDeferValidation()));
57+
}
5458
return request;
5559
}
5660

client/rest-high-level/src/main/java/org/elasticsearch/client/dataframe/PutDataFrameTransformRequest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131

3232
public class PutDataFrameTransformRequest implements ToXContentObject, Validatable {
3333

34+
public static final String DEFER_VALIDATION = "defer_validation";
3435
private final DataFrameTransformConfig config;
36+
private Boolean deferValidation;
3537

3638
public PutDataFrameTransformRequest(DataFrameTransformConfig config) {
3739
this.config = config;
@@ -41,6 +43,19 @@ public DataFrameTransformConfig getConfig() {
4143
return config;
4244
}
4345

46+
public Boolean getDeferValidation() {
47+
return deferValidation;
48+
}
49+
50+
/**
51+
* Indicates if deferrable validations should be skipped until the transform starts
52+
*
53+
* @param deferValidation {@code true} will cause validations to be deferred
54+
*/
55+
public void setDeferValidation(boolean deferValidation) {
56+
this.deferValidation = deferValidation;
57+
}
58+
4459
@Override
4560
public Optional<ValidationException> validate() {
4661
ValidationException validationException = new ValidationException();

client/rest-high-level/src/test/java/org/elasticsearch/client/DataFrameRequestConvertersTests.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,17 @@ public void testPutDataFrameTransform() throws IOException {
6868
PutDataFrameTransformRequest putRequest = new PutDataFrameTransformRequest(
6969
DataFrameTransformConfigTests.randomDataFrameTransformConfig());
7070
Request request = DataFrameRequestConverters.putDataFrameTransform(putRequest);
71-
71+
assertThat(request.getParameters(), not(hasKey("defer_validation")));
7272
assertEquals(HttpPut.METHOD_NAME, request.getMethod());
7373
assertThat(request.getEndpoint(), equalTo("/_data_frame/transforms/" + putRequest.getConfig().getId()));
7474

7575
try (XContentParser parser = createParser(JsonXContent.jsonXContent, request.getEntity().getContent())) {
7676
DataFrameTransformConfig parsedConfig = DataFrameTransformConfig.PARSER.apply(parser, null);
7777
assertThat(parsedConfig, equalTo(putRequest.getConfig()));
7878
}
79+
putRequest.setDeferValidation(true);
80+
request = DataFrameRequestConverters.putDataFrameTransform(putRequest);
81+
assertThat(request.getParameters(), hasEntry("defer_validation", Boolean.toString(putRequest.getDeferValidation())));
7982
}
8083

8184
public void testDeleteDataFrameTransform() {

client/rest-high-level/src/test/java/org/elasticsearch/client/DataFrameTransformIT.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,22 @@ public void testCreateDelete() throws IOException {
180180
assertThat(deleteError.getMessage(), containsString("Transform with id [test-crud] could not be found"));
181181
}
182182

183+
public void testCreateDeleteWithDefer() throws IOException {
184+
String sourceIndex = "missing-source-index";
185+
186+
String id = "test-with-defer";
187+
DataFrameTransformConfig transform = validDataFrameTransformConfig(id, sourceIndex, "pivot-dest");
188+
DataFrameClient client = highLevelClient().dataFrame();
189+
PutDataFrameTransformRequest request = new PutDataFrameTransformRequest(transform);
190+
request.setDeferValidation(true);
191+
AcknowledgedResponse ack = execute(request, client::putDataFrameTransform, client::putDataFrameTransformAsync);
192+
assertTrue(ack.isAcknowledged());
193+
194+
ack = execute(new DeleteDataFrameTransformRequest(transform.getId()), client::deleteDataFrameTransform,
195+
client::deleteDataFrameTransformAsync);
196+
assertTrue(ack.isAcknowledged());
197+
}
198+
183199
public void testGetTransform() throws IOException {
184200
String sourceIndex = "transform-source";
185201
createIndex(sourceIndex);

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/DataFrameTransformDocumentationIT.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public void testPutDataFrameTransform() throws IOException, InterruptedException
166166
// tag::put-data-frame-transform-request
167167
PutDataFrameTransformRequest request =
168168
new PutDataFrameTransformRequest(transformConfig); // <1>
169+
request.setDeferValidation(false); // <2>
169170
// end::put-data-frame-transform-request
170171

171172
// tag::put-data-frame-transform-execute

docs/java-rest/high-level/dataframe/put_data_frame.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ A +{request}+ requires the following argument:
2020
include-tagged::{doc-tests-file}[{api}-request]
2121
--------------------------------------------------
2222
<1> The configuration of the {dataframe-transform} to create
23+
<2> Whether or not to wait to run deferrable validations until `_start` is called.
24+
This option should be used with care as the created {dataframe-transform} will run
25+
with the privileges of the user creating it. Meaning, if they do not have privileges,
26+
such an error will not be visible until `_start` is called.
2327

2428
[id="{upid}-{api}-config"]
2529
==== Data Frame Transform Configuration

docs/reference/data-frames/apis/put-transform.asciidoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ IMPORTANT: You must use {kib} or this API to create a {dataframe-transform}.
4545
can contain lowercase alphanumeric characters (a-z and 0-9), hyphens, and
4646
underscores. It must start and end with alphanumeric characters.
4747

48+
[[put-data-frame-transform-query-parms]]
49+
==== {api-query-parms-title}
50+
51+
`defer_validation`::
52+
(Optional, boolean) When `true`, this will cause deferrable validations to not run.
53+
This behavior may be desired if the source index does not exist until
54+
after the the {dataframe-transform} is created.
55+
Deferred validations are always ran when the {dataframe-transform} is started,
56+
with the exception of privilege checks. If the user who created the transform does
57+
not have the required privileges on the source and destination indices then the
58+
transform will start but then fail when it attempts the unauthorized operation.
59+
60+
The default value is `false`.
61+
4862
[[put-data-frame-transform-request-body]]
4963
==== {api-request-body-title}
5064

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/dataframe/DataFrameField.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public final class DataFrameField {
3333
public static final ParseField SYNC = new ParseField("sync");
3434
public static final ParseField TIME_BASED_SYNC = new ParseField("time");
3535
public static final ParseField DELAY = new ParseField("delay");
36+
public static final ParseField DEFER_VALIDATION = new ParseField("defer_validation");
3637

3738
public static final ParseField ALLOW_NO_MATCH = new ParseField("allow_no_match");
3839
/**

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/dataframe/action/PutDataFrameTransformAction.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66

77
package org.elasticsearch.xpack.core.dataframe.action;
88

9+
import org.elasticsearch.Version;
910
import org.elasticsearch.action.ActionRequestValidationException;
1011
import org.elasticsearch.action.ActionType;
1112
import org.elasticsearch.action.support.master.AcknowledgedRequest;
1213
import org.elasticsearch.action.support.master.AcknowledgedResponse;
1314
import org.elasticsearch.common.io.stream.StreamInput;
1415
import org.elasticsearch.common.io.stream.StreamOutput;
1516
import org.elasticsearch.common.unit.TimeValue;
16-
import org.elasticsearch.common.xcontent.ToXContentObject;
17-
import org.elasticsearch.common.xcontent.XContentBuilder;
1817
import org.elasticsearch.common.xcontent.XContentParser;
1918
import org.elasticsearch.indices.InvalidIndexNameException;
2019
import org.elasticsearch.xpack.core.dataframe.DataFrameField;
@@ -41,21 +40,28 @@ private PutDataFrameTransformAction() {
4140
super(NAME, AcknowledgedResponse::new);
4241
}
4342

44-
public static class Request extends AcknowledgedRequest<Request> implements ToXContentObject {
43+
public static class Request extends AcknowledgedRequest<Request> {
4544

4645
private final DataFrameTransformConfig config;
46+
private final boolean deferValidation;
4747

48-
public Request(DataFrameTransformConfig config) {
48+
public Request(DataFrameTransformConfig config, boolean deferValidation) {
4949
this.config = config;
50+
this.deferValidation = deferValidation;
5051
}
5152

5253
public Request(StreamInput in) throws IOException {
5354
super(in);
5455
this.config = new DataFrameTransformConfig(in);
56+
if (in.getVersion().onOrAfter(Version.CURRENT)) {
57+
this.deferValidation = in.readBoolean();
58+
} else {
59+
this.deferValidation = false;
60+
}
5561
}
5662

57-
public static Request fromXContent(final XContentParser parser, final String id) throws IOException {
58-
return new Request(DataFrameTransformConfig.fromXContent(parser, id, false));
63+
public static Request fromXContent(final XContentParser parser, final String id, final boolean deferValidation) {
64+
return new Request(DataFrameTransformConfig.fromXContent(parser, id, false), deferValidation);
5965
}
6066

6167
/**
@@ -111,24 +117,26 @@ public ActionRequestValidationException validate() {
111117
return validationException;
112118
}
113119

114-
@Override
115-
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
116-
return this.config.toXContent(builder, params);
117-
}
118-
119120
public DataFrameTransformConfig getConfig() {
120121
return config;
121122
}
122123

124+
public boolean isDeferValidation() {
125+
return deferValidation;
126+
}
127+
123128
@Override
124129
public void writeTo(StreamOutput out) throws IOException {
125130
super.writeTo(out);
126131
this.config.writeTo(out);
132+
if (out.getVersion().onOrAfter(Version.CURRENT)) {
133+
out.writeBoolean(this.deferValidation);
134+
}
127135
}
128136

129137
@Override
130138
public int hashCode() {
131-
return Objects.hash(config);
139+
return Objects.hash(config, deferValidation);
132140
}
133141

134142
@Override
@@ -140,7 +148,7 @@ public boolean equals(Object obj) {
140148
return false;
141149
}
142150
Request other = (Request) obj;
143-
return Objects.equals(config, other.config);
151+
return Objects.equals(config, other.config) && this.deferValidation == other.deferValidation;
144152
}
145153
}
146154

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/dataframe/action/PutDataFrameTransformActionRequestTests.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,49 @@
66

77
package org.elasticsearch.xpack.core.dataframe.action;
88

9+
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
910
import org.elasticsearch.common.io.stream.Writeable;
10-
import org.elasticsearch.common.xcontent.XContentParser;
11+
import org.elasticsearch.common.settings.Settings;
12+
import org.elasticsearch.search.SearchModule;
13+
import org.elasticsearch.test.AbstractWireSerializingTestCase;
14+
import org.elasticsearch.xpack.core.dataframe.DataFrameField;
1115
import org.elasticsearch.xpack.core.dataframe.action.PutDataFrameTransformAction.Request;
1216
import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformConfig;
1317
import org.elasticsearch.xpack.core.dataframe.transforms.DataFrameTransformConfigTests;
18+
import org.elasticsearch.xpack.core.dataframe.transforms.SyncConfig;
19+
import org.elasticsearch.xpack.core.dataframe.transforms.TimeSyncConfig;
1420
import org.junit.Before;
1521

16-
import java.io.IOException;
22+
import java.util.List;
1723

18-
public class PutDataFrameTransformActionRequestTests extends AbstractSerializingDataFrameTestCase<Request> {
24+
import static java.util.Collections.emptyList;
25+
26+
public class PutDataFrameTransformActionRequestTests extends AbstractWireSerializingTestCase<Request> {
1927
private String transformId;
2028

2129
@Before
2230
public void setupTransformId() {
2331
transformId = randomAlphaOfLengthBetween(1, 10);
2432
}
2533

26-
@Override
27-
protected Request doParseInstance(XContentParser parser) throws IOException {
28-
return Request.fromXContent(parser, transformId);
29-
}
30-
3134
@Override
3235
protected Writeable.Reader<Request> instanceReader() {
3336
return Request::new;
3437
}
3538

3639
@Override
37-
protected boolean supportsUnknownFields() {
38-
return false;
40+
protected Request createTestInstance() {
41+
DataFrameTransformConfig config = DataFrameTransformConfigTests.randomDataFrameTransformConfigWithoutHeaders(transformId);
42+
return new Request(config, randomBoolean());
3943
}
4044

4145
@Override
42-
protected Request createTestInstance() {
43-
DataFrameTransformConfig config = DataFrameTransformConfigTests.randomDataFrameTransformConfigWithoutHeaders(transformId);
44-
return new Request(config);
46+
protected NamedWriteableRegistry getNamedWriteableRegistry() {
47+
SearchModule searchModule = new SearchModule(Settings.EMPTY, emptyList());
48+
49+
List<NamedWriteableRegistry.Entry> namedWriteables = searchModule.getNamedWriteables();
50+
namedWriteables.add(new NamedWriteableRegistry.Entry(SyncConfig.class, DataFrameField.TIME_BASED_SYNC.getPreferredName(),
51+
TimeSyncConfig::new));
52+
return new NamedWriteableRegistry(namedWriteables);
4553
}
4654
}

0 commit comments

Comments
 (0)