Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HLRC: migration api - upgrade #34898

Merged
merged 14 commits into from Nov 13, 2018

Conversation

pgomulka
Copy link
Contributor

@pgomulka pgomulka commented Oct 26, 2018

Implement high level client for migration upgrade API. It should wrap RestHighLevelClient and expose high level IndexUpgradeRequest (new) & BulkByScrollResponse (already used) objects.

endpoints:
sync & async:
POST /_xpack/migration/upgrade/<index_name>
sync with task api:
POST /_xpack/migration/upgrade/.watches?wait_for_completion=false

links:
Documentation reference:
https://www.elastic.co/guide/en/elasticsearch/reference/current/migration-api-assistance.html
X-pack API:
https://github.com/elastic/elasticsearch/blob/master/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.migration.get_assistance.json

refers: #29827

@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

BulkByScrollResponse::fromXContent, Collections.emptySet());
}

public IndexUpgradeSubmissionResponse submitUpgradeTask(IndexUpgradeRequest request, RequestOptions options) throws IOException {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as discussed, I want to refactor that later to return TaskSubmissionResponse and use across other methods where wait_for_completion=false was used

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is another PR where we discussed if it wouldn't be better to return just TaskID:
https://github.com/elastic/elasticsearch/pull/35202/files
I might get back to this one and refactor to this TaskID

@@ -80,4 +92,72 @@ public void testGetAssistance() throws IOException {
}
// end::get-assistance-response
}

public void testUpgrade() throws IOException {
Copy link
Contributor Author

@pgomulka pgomulka Oct 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here I am adding these test cases which are duplicates of the one I have in MigrationIT. I made it more documentation friendly here though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

import java.util.Arrays;
import java.util.Objects;

public class IndexUpgradeRequest extends MasterNodeReadRequest<IndexUpgradeRequest> implements IndicesRequest {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this request allows only one index to be used - as per rest spec - however the interface returns arrays. might be a bit confusing..

indices = new String[]{index};
}

public IndexUpgradeRequest(StreamInput in) throws IOException {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be safe, I was looking into how IndexUpgradeInfo was implemented, copied that class and removed some methods that were not needed. Not sure if we really need this constructor. This is probably how this could be used on the server side, but that class is intended to be used on client side only. Should I remove it too?

/**
* Response object that contains the taskID from submitted IndexUpgradeRequest
*/
public class IndexUpgradeSubmissionResponse extends ActionResponse implements ToXContentObject {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as mentioned earlier - this will be refactored later

@pgomulka
Copy link
Contributor Author

@hub-cap would you like to have a look into this one?

Implement high level client for migration upgrade API. It should wrap
RestHighLevelClient and expose high level IndexUpgradeRequest (new),
IndexTaskResponse for submissions with wait_for_completion=false and
BulkByScrollResponse (already used) objects.

refers: elastic#29827
return putParam("wait_for_completion", Boolean.TRUE.toString());
}
return this;
return putParam("wait_for_completion", Boolean.toString(waitForCompletion));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that need to be to set false and pass through to the server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, this is due to the fact that wait_for_completion defaults to true in this API, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly. See RestIndexUpgradeAction:60
if (request.paramAsBoolean("wait_for_completion", true)) {

@@ -0,0 +1,79 @@
[[java-rest-high-migration-upgrade]]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a lot of duplication between this and for instance bulk api doc. Probably some refactoring to remove doc duplication would be welcome

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea i think that we can wait till docs squares away what they are doing with our rest api docs before diving in to this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Copy link
Contributor

@hub-cap hub-cap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, getting close to finishing this! Thanks for all the thought around the task work too. Some nits mostly and the test comment below.

Please have a look at the test cases that recent HLRC APIs have done for the response objects. Lets add one for the submission response.

BulkByScrollResponse::fromXContent, Collections.emptySet());
}

public IndexUpgradeSubmissionResponse submitUpgradeTask(IndexUpgradeRequest request, RequestOptions options) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++.

return putParam("wait_for_completion", Boolean.TRUE.toString());
}
return this;
return putParam("wait_for_completion", Boolean.toString(waitForCompletion));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, this is due to the fact that wait_for_completion defaults to true in this API, right?

import java.util.Arrays;
import java.util.Objects;

public class IndexUpgradeRequest extends MasterNodeReadRequest<IndexUpgradeRequest> implements IndicesRequest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some javadoc here pls

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

this.task = task;
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove a space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

new IndexUpgradeInfoRequest("test"), RequestOptions.DEFAULT);
assertEquals(0, response.getActions().size());
}
}

public void testUpgrade() throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a failure case in the test itself but the name of the method does not seem to reflect that. Something like testUpgradeIndexCannotBeUpgraded (feel free to name it yourself, im not a stickler on names).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea. Sadly this is not possible to test easily the real upgrade

private BooleanSupplier checkCompletionStatus(IndexUpgradeSubmissionResponse upgrade) {
return () -> {
try {
Response response = client().performRequest(new Request("GET", "/_tasks/" + upgrade.getTask().toString()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls put a note saying why this is low level rest (the tasks api has not been finished yet etc).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do- will leave a TODO note to revisit once the high level api for getTaskByID is finished

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

@@ -80,4 +92,72 @@ public void testGetAssistance() throws IOException {
}
// end::get-assistance-response
}

public void testUpgrade() throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

BulkByScrollResponse response = client.migration().upgrade(request, RequestOptions.DEFAULT);
// end::upgrade-execute

}catch(ElasticsearchStatusException e){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space }catch(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

++

@@ -0,0 +1,79 @@
[[java-rest-high-migration-upgrade]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea i think that we can wait till docs squares away what they are doing with our rest api docs before diving in to this.


import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester;

public class IndexUpgradeSubmissionResponseTests extends ESTestCase {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test will be refactor once we introduce a common task submission response class. Likely it would be just TaskId

@pgomulka
Copy link
Contributor Author

pgomulka commented Nov 5, 2018

@hub-cap updated the PR with review followup. Would you be able to have a look again?

Copy link
Contributor

@hub-cap hub-cap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting close. Great work with the thought behind the sync/async/submit stuff.

IndexUpgradeSubmissionResponse::fromXContent, Collections.emptySet());
}


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spaces

}

@Override
public void writeTo(StreamOutput out) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removing

indices = new String[]{index};
}

public IndexUpgradeRequest(StreamInput in) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, removing

* A request for performing Upgrade on Index
* Part of Migration API
*/
public class IndexUpgradeRequest extends MasterNodeReadRequest<IndexUpgradeRequest> implements IndicesRequest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be just a TimedRequest instead of a MasterNodeReadRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree, great suggestion

}

@Override
public ActionRequestValidationException validate() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove this once we make it a TimedRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

@Override
public void readFrom(StreamInput in) throws IOException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removed

import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.tasks.TaskId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a TaskId? Can we just use a string here instead? Id love to not pull things in from server here if possible

Copy link
Contributor Author

@pgomulka pgomulka Nov 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, that is not ideal that it uses a class from server, but maybe we could copy or make our own TaskId class in HLRC?
I am a big fan of strong typed apis, and that abstracts nicely the concept of task identifier. I could refactor this class now, but since this is used in reindex and in getTask PRs I would prefer to refactor later

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO if we always pass it to server as a single string and never need to modify it or make decisions based on some portion of the ID (as i understand it has > 1 bit of information in the string separated by a delimiter), then making it a string is fine by me.

That being said, if it is easier for a user to create a object with those 3 values rather than just passing in a string, Im all for using an object.

I dont know all the uses, but im a fan of keeping it simple. If a user is never going to do anything with those 3 different parts of the string, and they only store it and give it back to us as a single string, it does not make much sense in my mind to create a class representation for the 3 strings. Ofc it might make sense to have this on the server, since those 3 strings are useful as individual pieces :D

All that being said, im ok with duplicating a TaskId class in HLRC. Im not too picky :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What @hub-cap said. I too am unclear on the uses of TaskIDs and whether clients would need to break out component parts. I suppose even if they don't there's a potential upside to a typed object just because we could make them have private constructors so a client would only ever be able to give us IDs we'd previously given them, rather than any arbitrary string of their choosing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im still leaning toward string. we have to have a way to deserialize bits from the wire into a TaskId, so there will be a way for a user to create their own TaskId, if they want to go that far.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am convinced too. Will refactor this to use TaskSubmissionResponse with taskId field of type String

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. In retrospect, typed TaskIDs might only be useful if the world ran on Java but Java apps will typically hand off control to a Javascript front-end where it would become untyped strings in subsequent comms.

private BooleanSupplier checkCompletionStatus(IndexUpgradeSubmissionResponse upgrade) {
return () -> {
try {
Response response = client().performRequest(new Request("GET", "/_tasks/" + upgrade.getTask().toString()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3

Copy link
Contributor

@hub-cap hub-cap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the docs can be DRY'd up (see #34925), and Id like to get the String VS TaskId issue solved, but then this will be good to merge.


private static Request prepareMigrateRequest(IndexUpgradeRequest indexUpgradeRequest, boolean waitForCompletion) {
RequestConverters.EndpointBuilder endpointBuilder = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_xpack/migration/upgrade")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can comma separate these instead... i know the likelihood of us not using / is low, but its best to not have them in this.

* A request for performing Upgrade on Index
* Part of Migration API
*/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line

* Part of Migration API
*/

public class IndexUpgradeRequest extends TimedRequest implements IndicesRequest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this IndicesRequest? We know that we should provide a getter for the IndicesOptions so im ok w/ removing this and the override as well.

import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.tasks.TaskId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im still leaning toward string. we have to have a way to deserialize bits from the wire into a TaskId, so there will be a way for a user to create their own TaskId, if they want to go that far.

@pgomulka
Copy link
Contributor Author

pgomulka commented Nov 9, 2018

@hub-cap updated PR and build is passing too!

Copy link
Contributor

@hub-cap hub-cap left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One nit and one question, other than that lgtm. Im approving but I would still like ot see the answer to the question about array vs single string.

@@ -49,13 +50,14 @@ static Request submitMigrateTask(IndexUpgradeRequest indexUpgradeRequest) {

private static Request prepareMigrateRequest(IndexUpgradeRequest indexUpgradeRequest, boolean waitForCompletion) {
RequestConverters.EndpointBuilder endpointBuilder = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_xpack/migration/upgrade")
.addCommaSeparatedPathParts(indexUpgradeRequest.indices());
.addPathPartAsIs("_xpack", "migration", "upgrade", indexUpgradeRequest.index());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has to be

.addPathPartAsIs("Strings", "hard", "coded")
.addPathPart(indexUpgradeRequest.index())

for sanitization


private String[] indices;
private IndicesOptions indicesOptions = IndicesOptions.fromOptions(false, true, true, true);
private String index;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we change this from an array of strings to a single one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for other kind of requests you can specify indices comma separated like _xpack/migration/assistance/index1,index2,index3
but for upgrade only one is allowed (as per documentation)

@pgomulka pgomulka merged commit fd4cd80 into elastic:master Nov 13, 2018
pgomulka added a commit to pgomulka/elasticsearch that referenced this pull request Nov 14, 2018
Implement high level client for migration upgrade API. It should wrap
RestHighLevelClient and expose high level IndexUpgradeRequest (new),
IndexTaskResponse for submissions with wait_for_completion=false and
BulkByScrollResponse (already used) objects.

refers: elastic#29827
pgomulka added a commit to pgomulka/elasticsearch that referenced this pull request Nov 14, 2018
Implement high level client for migration upgrade API. It should wrap
RestHighLevelClient and expose high level IndexUpgradeRequest (new),
IndexTaskResponse for submissions with wait_for_completion=false and
BulkByScrollResponse (already used) objects.

refers: elastic#29827
pgomulka added a commit that referenced this pull request Nov 15, 2018
Implement high level client for migration upgrade API. It should wrap
RestHighLevelClient and expose high level IndexUpgradeRequest (new),
IndexTaskResponse for submissions with wait_for_completion=false and
BulkByScrollResponse (already used) objects.

refers: #29827
Original backported PR (#34898)
PR of the backport (#35528)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants