Skip to content

Commit

Permalink
Merge branch 'master' into redhat-release
Browse files Browse the repository at this point in the history
* master:
  Address handling of OS pretty name on some OS (elastic#35451)
  HLRC support for getTask (elastic#35166)
  upgrade to lucene-8.0.0-snapshot-6d9c714052 (elastic#35428)
  Add docs for CCR stats API (elastic#35439)
  Fix the names of CCR stats endpoints in usage API (elastic#35438)
  Switch to default to no build qualifier (elastic#35415)
  Clarify S3 repository storage class parameter (elastic#35400)
  SQL: Fix query translation for scripted queries (elastic#35408)
  [TEST] Instead of ignoring the ccr downgrade to basic license qa test avoid the assertions that check the log files, because that does not work on Windows. The rest of the test is still useful and should work on Windows CI.
  Upgrade to Joda 2.10.1 (elastic#35410)
  HLRest: model role and privileges (elastic#35128)
  • Loading branch information
jasontedor committed Nov 12, 2018
2 parents c09423d + 40ca62c commit f802b9a
Show file tree
Hide file tree
Showing 92 changed files with 2,018 additions and 144 deletions.
2 changes: 1 addition & 1 deletion buildSrc/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class VersionPropertiesLoader {
elasticsearch
)
}
String qualifier = systemProperties.getProperty("build.version_qualifier", "alpha1");
String qualifier = systemProperties.getProperty("build.version_qualifier", "");
if (qualifier.isEmpty() == false) {
if (qualifier.matches("(alpha|beta|rc)\\d+") == false) {
throw new IllegalStateException("Invalid qualifier: " + qualifier)
Expand Down
3 changes: 2 additions & 1 deletion buildSrc/version.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
elasticsearch = 7.0.0
lucene = 8.0.0-snapshot-31d7dfe6b1
lucene = 8.0.0-snapshot-6d9c714052

# optional dependencies
spatial4j = 0.7
Expand All @@ -16,6 +16,7 @@ slf4j = 1.6.2
jna = 4.5.1

netty = 4.1.30.Final
joda = 2.10.1

# test dependencies
randomizedrunner = 2.7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1417,6 +1417,38 @@ private <Req, Resp> Resp internalPerformRequest(Req request,
throw new IOException("Unable to parse response body for " + response, e);
}
}

/**
* Defines a helper method for requests that can 404 and in which case will return an empty Optional
* otherwise tries to parse the response body
*/
protected final <Req extends Validatable, Resp> Optional<Resp> performRequestAndParseOptionalEntity(Req request,
CheckedFunction<Req, Request, IOException> requestConverter,
RequestOptions options,
CheckedFunction<XContentParser, Resp, IOException> entityParser
) throws IOException {
Optional<ValidationException> validationException = request.validate();
if (validationException != null && validationException.isPresent()) {
throw validationException.get();
}
Request req = requestConverter.apply(request);
req.setOptions(options);
Response response;
try {
response = client.performRequest(req);
} catch (ResponseException e) {
if (RestStatus.NOT_FOUND.getStatus() == e.getResponse().getStatusLine().getStatusCode()) {
return Optional.empty();
}
throw parseResponseException(e);
}

try {
return Optional.of(parseEntity(response.getEntity(), entityParser));
} catch (Exception e) {
throw new IOException("Unable to parse response body for " + response, e);
}
}

/**
* @deprecated If creating a new HLRC ReST API call, consider creating new actions instead of reusing server actions. The Validation
Expand Down Expand Up @@ -1538,6 +1570,62 @@ public void onFailure(Exception exception) {
}
};
}

/**
* Async request which returns empty Optionals in the case of 404s or parses entity into an Optional
*/
protected final <Req extends Validatable, Resp> void performRequestAsyncAndParseOptionalEntity(Req request,
CheckedFunction<Req, Request, IOException> requestConverter,
RequestOptions options,
CheckedFunction<XContentParser, Resp, IOException> entityParser,
ActionListener<Optional<Resp>> listener) {
Optional<ValidationException> validationException = request.validate();
if (validationException != null && validationException.isPresent()) {
listener.onFailure(validationException.get());
return;
}
Request req;
try {
req = requestConverter.apply(request);
} catch (Exception e) {
listener.onFailure(e);
return;
}
req.setOptions(options);
ResponseListener responseListener = wrapResponseListener404sOptional(response -> parseEntity(response.getEntity(),
entityParser), listener);
client.performRequestAsync(req, responseListener);
}

final <Resp> ResponseListener wrapResponseListener404sOptional(CheckedFunction<Response, Resp, IOException> responseConverter,
ActionListener<Optional<Resp>> actionListener) {
return new ResponseListener() {
@Override
public void onSuccess(Response response) {
try {
actionListener.onResponse(Optional.of(responseConverter.apply(response)));
} catch (Exception e) {
IOException ioe = new IOException("Unable to parse response body for " + response, e);
onFailure(ioe);
}
}

@Override
public void onFailure(Exception exception) {
if (exception instanceof ResponseException) {
ResponseException responseException = (ResponseException) exception;
Response response = responseException.getResponse();
if (RestStatus.NOT_FOUND.getStatus() == response.getStatusLine().getStatusCode()) {
actionListener.onResponse(Optional.empty());
} else {
actionListener.onFailure(parseResponseException(responseException));
}
} else {
actionListener.onFailure(exception);
}
}
};
}

/**
* Converts a {@link ResponseException} obtained from the low level REST client into an {@link ElasticsearchException}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksResponse;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
import org.elasticsearch.client.tasks.GetTaskRequest;
import org.elasticsearch.client.tasks.GetTaskResponse;

import java.io.IOException;
import java.util.Optional;

import static java.util.Collections.emptySet;

Expand Down Expand Up @@ -67,6 +70,34 @@ public void listAsync(ListTasksRequest request, RequestOptions options, ActionLi
restHighLevelClient.performRequestAsyncAndParseEntity(request, TasksRequestConverters::listTasks, options,
ListTasksResponse::fromXContent, listener, emptySet());
}

/**
* Get a task using the Task Management API.
* See
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html"> Task Management API on elastic.co</a>
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
*/
public Optional<GetTaskResponse> get(GetTaskRequest request, RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseOptionalEntity(request, TasksRequestConverters::getTask, options,
GetTaskResponse::fromXContent);
}

/**
* Get a task using the Task Management API.
* See
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html"> Task Management API on elastic.co</a>
* @param request the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener an actionlistener that takes an optional response (404s are returned as an empty Optional)
*/
public void getAsync(GetTaskRequest request, RequestOptions options, ActionListener<Optional<GetTaskResponse>> listener) {

restHighLevelClient.performRequestAsyncAndParseOptionalEntity(request, TasksRequestConverters::getTask, options,
GetTaskResponse::fromXContent, listener);
}

/**
* Cancel one or more cluster tasks using the Task Management API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import org.apache.http.client.methods.HttpPost;
import org.elasticsearch.action.admin.cluster.node.tasks.cancel.CancelTasksRequest;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
import org.elasticsearch.client.RequestConverters.EndpointBuilder;
import org.elasticsearch.client.tasks.GetTaskRequest;

final class TasksRequestConverters {

Expand Down Expand Up @@ -54,4 +56,16 @@ static Request listTasks(ListTasksRequest listTaskRequest) {
.putParam("group_by", "none");
return request;
}

static Request getTask(GetTaskRequest getTaskRequest) {
String endpoint = new EndpointBuilder().addPathPartAsIs("_tasks")
.addPathPartAsIs(getTaskRequest.getNodeId() + ":" + Long.toString(getTaskRequest.getTaskId()))
.build();
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
RequestConverters.Params params = new RequestConverters.Params(request);
params.withTimeout(getTaskRequest.getTimeout())
.withWaitForCompletion(getTaskRequest.getWaitForCompletion());
return request;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.client.security.user.privileges;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;

/**
* Represents privileges over resources that are scoped under an application.
* The application, resources and privileges are completely managed by the
* client and can be arbitrary string identifiers. Elasticsearch is not
* concerned by any resources under an application scope.
*/
public final class ApplicationResourcePrivileges implements ToXContentObject {

private static final ParseField APPLICATION = new ParseField("application");
private static final ParseField PRIVILEGES = new ParseField("privileges");
private static final ParseField RESOURCES = new ParseField("resources");

@SuppressWarnings("unchecked")
static final ConstructingObjectParser<ApplicationResourcePrivileges, Void> PARSER = new ConstructingObjectParser<>(
"application_privileges", false, constructorObjects -> {
// Don't ignore unknown fields. It is dangerous if the object we parse is also
// part of a request that we build later on, and the fields that we now ignore will
// end up being implicitly set to null in that request.
int i = 0;
final String application = (String) constructorObjects[i++];
final Collection<String> privileges = (Collection<String>) constructorObjects[i++];
final Collection<String> resources = (Collection<String>) constructorObjects[i];
return new ApplicationResourcePrivileges(application, privileges, resources);
});

static {
PARSER.declareString(constructorArg(), APPLICATION);
PARSER.declareStringArray(constructorArg(), PRIVILEGES);
PARSER.declareStringArray(constructorArg(), RESOURCES);
}

private final String application;
private final Set<String> privileges;
private final Set<String> resources;

/**
* Constructs privileges for resources under an application scope.
*
* @param application
* The application name. This identifier is completely under the
* clients control.
* @param privileges
* The privileges names. Cannot be null or empty. Privilege
* identifiers are completely under the clients control.
* @param resources
* The resources names. Cannot be null or empty. Resource identifiers
* are completely under the clients control.
*/
public ApplicationResourcePrivileges(String application, Collection<String> privileges, Collection<String> resources) {
if (Strings.isNullOrEmpty(application)) {
throw new IllegalArgumentException("application privileges must have an application name");
}
if (null == privileges || privileges.isEmpty()) {
throw new IllegalArgumentException("application privileges must define at least one privilege");
}
if (null == resources || resources.isEmpty()) {
throw new IllegalArgumentException("application privileges must refer to at least one resource");
}
this.application = application;
this.privileges = Collections.unmodifiableSet(new HashSet<>(privileges));
this.resources = Collections.unmodifiableSet(new HashSet<>(resources));
}

public String getApplication() {
return application;
}

public Set<String> getResources() {
return this.resources;
}

public Set<String> getPrivileges() {
return this.privileges;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || this.getClass() != o.getClass()) {
return false;
}
ApplicationResourcePrivileges that = (ApplicationResourcePrivileges) o;
return application.equals(that.application)
&& privileges.equals(that.privileges)
&& resources.equals(that.resources);
}

@Override
public int hashCode() {
return Objects.hash(application, privileges, resources);
}

@Override
public String toString() {
try {
return XContentHelper.toXContent(this, XContentType.JSON, true).utf8ToString();
} catch (IOException e) {
throw new RuntimeException("Unexpected", e);
}
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field(APPLICATION.getPreferredName(), application);
builder.field(PRIVILEGES.getPreferredName(), privileges);
builder.field(RESOURCES.getPreferredName(), resources);
return builder.endObject();
}

public static ApplicationResourcePrivileges fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}

}

0 comments on commit f802b9a

Please sign in to comment.