All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.janusgraph.diskstorage.es.rest.RestClientSetup Maven / Gradle / Ivy

There is a newer version: 1.2.0-20241116-110554.8064ac9
Show newest version
// Copyright 2017 JanusGraph Authors
//
// Licensed 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.janusgraph.diskstorage.es.rest;

import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.elasticsearch.client.RestClientBuilder.RequestConfigCallback;
import org.janusgraph.diskstorage.configuration.ConfigOption;
import org.janusgraph.diskstorage.configuration.Configuration;
import org.janusgraph.diskstorage.es.ElasticSearchClient;
import org.janusgraph.diskstorage.es.ElasticSearchIndex;
import org.janusgraph.diskstorage.es.rest.util.BasicAuthHttpClientConfigCallback;
import org.janusgraph.diskstorage.es.rest.util.ConnectionKeepAliveConfigCallback;
import org.janusgraph.diskstorage.es.rest.util.HttpAuthTypes;
import org.janusgraph.diskstorage.es.rest.util.RestClientAuthenticator;
import org.janusgraph.diskstorage.es.rest.util.SSLConfigurationCallback;
import org.janusgraph.diskstorage.es.rest.util.SSLConfigurationCallback.Builder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.INDEX_HOSTS;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.INDEX_PORT;

/**
 * Create an instance of Elasticsearch REST {@link org.elasticsearch.client.RestClient} from a JanusGraph
 * {@link org.janusgraph.diskstorage.configuration.Configuration}.
 */
public class RestClientSetup {

    private static final Logger log = LoggerFactory.getLogger(RestClientSetup.class);

    public ElasticSearchClient connect(Configuration config) throws IOException {
        log.debug("Configuring RestClient");

        final List hosts = new ArrayList<>();
        final int defaultPort = config.has(INDEX_PORT) ? config.get(INDEX_PORT) : ElasticSearchIndex.HOST_PORT_DEFAULT;
        final String httpScheme = config.get(ElasticSearchIndex.SSL_ENABLED) ? "https" : "http";
        for (String host : config.get(INDEX_HOSTS)) {
            String[] hostStringParts = host.split(":");
            String hostname = hostStringParts[0];
            int hostPort = defaultPort;
            if (hostStringParts.length == 2) hostPort = Integer.parseInt(hostStringParts[1]);
            log.debug("Configured remote host: {} : {}", hostname, hostPort);
            hosts.add(new HttpHost(hostname, hostPort, httpScheme));
        }

        final RestClient rc = getRestClient(hosts.toArray(new HttpHost[hosts.size()]), config);

        final int scrollKeepAlive = config.get(ElasticSearchIndex.ES_SCROLL_KEEP_ALIVE);
        Preconditions.checkArgument(scrollKeepAlive >= 1, "Scroll keep-alive should be greater than or equal to 1");
        final boolean useMappingTypesForES7 = config.get(ElasticSearchIndex.USE_MAPPING_FOR_ES7);
        int retryLimit = config.getOrDefault(ElasticSearchIndex.RETRY_LIMIT);
        long retryInitialWaitMs = config.getOrDefault(ElasticSearchIndex.RETRY_INITIAL_WAIT);
        long retryMaxWaitMs = config.getOrDefault(ElasticSearchIndex.RETRY_MAX_WAIT);
        Set errorCodesToRetry = Arrays.stream(config.getOrDefault(ElasticSearchIndex.RETRY_ERROR_CODES))
            .mapToInt(Integer::parseInt).boxed().collect(Collectors.toSet());
        int bulkChunkLimitBytes = config.getOrDefault(ElasticSearchIndex.BULK_CHUNK_SIZE_LIMIT_BYTES);
        final RestElasticSearchClient client = getElasticSearchClient(rc, scrollKeepAlive, useMappingTypesForES7,
            retryLimit, errorCodesToRetry, retryInitialWaitMs, retryMaxWaitMs, bulkChunkLimitBytes);
        if (config.has(ElasticSearchIndex.BULK_REFRESH)) {
            client.setBulkRefresh(config.get(ElasticSearchIndex.BULK_REFRESH));
        }

        Integer retryOnConflict = config.has(ElasticSearchIndex.RETRY_ON_CONFLICT) ? config.get(ElasticSearchIndex.RETRY_ON_CONFLICT) : null;
        client.setRetryOnConflict(retryOnConflict);

        return client;
    }

    protected RestClient getRestClient(HttpHost[] hosts, Configuration config) {
        final RestClientBuilder restClientBuilder = getRestClientBuilder(hosts);

        final HttpClientConfigCallback httpClientConfigCallback = getHttpClientConfigCallback(config);
        if (httpClientConfigCallback != null) {
            restClientBuilder.setHttpClientConfigCallback(httpClientConfigCallback);
        }

        final RequestConfigCallback requestConfigCallback = getRequestConfigCallback(config);
        if (requestConfigCallback != null) {
            restClientBuilder.setRequestConfigCallback(requestConfigCallback);
        }

        return restClientBuilder.build();
    }

    protected RestClientBuilder getRestClientBuilder(HttpHost[] hosts) {
        return RestClient.builder(hosts);
    }

    protected RestElasticSearchClient getElasticSearchClient(RestClient rc, int scrollKeepAlive, boolean useMappingTypesForES7,
                                                             int retryAttemptLimit, Set retryOnErrorCodes, long retryInitialWaitMs,
                                                             long retryMaxWaitMs, int bulkChunkSerializedLimit) {
        return new RestElasticSearchClient(rc, scrollKeepAlive, useMappingTypesForES7, retryAttemptLimit, retryOnErrorCodes,
            retryInitialWaitMs, retryMaxWaitMs, bulkChunkSerializedLimit);
    }

    /**
     * 

* Returns the callback for customizing the {@link RequestConfig} or null if no * customization is needed. *

*

* See {@link RestClientBuilder#setRequestConfigCallback(RequestConfigCallback)} for more details. *

* * @param config * ES index configuration * @return callback or null if the request customization is not needed */ protected RequestConfigCallback getRequestConfigCallback(Configuration config) { final List callbackList = new LinkedList<>(); final Integer connectTimeout = config.get(ElasticSearchIndex.CONNECT_TIMEOUT); final Integer socketTimeout = config.get(ElasticSearchIndex.SOCKET_TIMEOUT); callbackList.add((requestConfigBuilder) -> requestConfigBuilder.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout)); // will execute the chain of individual callbacks return requestConfigBuilder -> { for(RequestConfigCallback cb: callbackList) { cb.customizeRequestConfig(requestConfigBuilder); } return requestConfigBuilder; }; } /** *

* Returns the callback for customizing {@link CloseableHttpAsyncClient} or null if no * customization is needed. *

*

* See {@link RestClientBuilder#setHttpClientConfigCallback(HttpClientConfigCallback)} for more details. *

* * @param config * ES index configuration * @return callback or null if the client customization is not needed */ protected HttpClientConfigCallback getHttpClientConfigCallback(Configuration config) { final List callbackList = new LinkedList<>(); final HttpAuthTypes authType = ConfigOption.getEnumValue(config.get(ElasticSearchIndex.ES_HTTP_AUTH_TYPE), HttpAuthTypes.class); log.debug("Configuring HTTP(S) authentication type {}", authType); switch (authType) { case BASIC: callbackList.add(new BasicAuthHttpClientConfigCallback( config.has(ElasticSearchIndex.ES_HTTP_AUTH_REALM) ? config.get(ElasticSearchIndex.ES_HTTP_AUTH_REALM) : "", config.get(ElasticSearchIndex.ES_HTTP_AUTH_USERNAME), config.get(ElasticSearchIndex.ES_HTTP_AUTH_PASSWORD))); break; case CUSTOM: callbackList.add(getCustomAuthenticator( config.get(ElasticSearchIndex.ES_HTTP_AUTHENTICATOR_CLASS), config.get(ElasticSearchIndex.ES_HTTP_AUTHENTICATOR_ARGS))); break; case NONE: break; default: // not expected throw new IllegalArgumentException("Authentication type \"" + authType + "\" is not implemented"); } if (config.has(ElasticSearchIndex.CLIENT_KEEP_ALIVE )) { callbackList.add(new ConnectionKeepAliveConfigCallback(config.get(ElasticSearchIndex.CLIENT_KEEP_ALIVE))); } if (config.get(ElasticSearchIndex.SSL_ENABLED)) { // Custom SSL configuration final Builder sslConfCBBuilder = getSSLConfigurationCallbackBuilder(); boolean configureSSL = false; if (config.has(ElasticSearchIndex.SSL_TRUSTSTORE_LOCATION)) { sslConfCBBuilder.withTrustStore(config.get(ElasticSearchIndex.SSL_TRUSTSTORE_LOCATION), config.get(ElasticSearchIndex.SSL_TRUSTSTORE_PASSWORD)); configureSSL = true; } if (config.has(ElasticSearchIndex.SSL_KEYSTORE_LOCATION)) { final String keystorePassword = config.get(ElasticSearchIndex.SSL_KEYSTORE_PASSWORD); sslConfCBBuilder.withKeyStore(config.get(ElasticSearchIndex.SSL_KEYSTORE_LOCATION), keystorePassword, config.has(ElasticSearchIndex.SSL_KEY_PASSWORD) ? config.get(ElasticSearchIndex.SSL_KEY_PASSWORD) : keystorePassword); configureSSL = true; } if (config.has(ElasticSearchIndex.SSL_DISABLE_HOSTNAME_VERIFICATION) && config.get(ElasticSearchIndex.SSL_DISABLE_HOSTNAME_VERIFICATION)) { log.warn("SSL hostname verification is disabled, Elasticsearch HTTPS connections may not be secure"); sslConfCBBuilder.disableHostNameVerification(); configureSSL = true; } if (config.has(ElasticSearchIndex.SSL_ALLOW_SELF_SIGNED_CERTIFICATES) && config.get(ElasticSearchIndex.SSL_ALLOW_SELF_SIGNED_CERTIFICATES)) { log.warn("Self-signed SSL certificate support is enabled, Elasticsearch HTTPS connections may not be secure"); sslConfCBBuilder.allowSelfSignedCertificates(); configureSSL = true; } if (configureSSL) { callbackList.add(sslConfCBBuilder.build()); } } if (callbackList.isEmpty()) { return null; } // will execute the chain of individual callbacks return httpClientBuilder -> { for(HttpClientConfigCallback cb: callbackList) { cb.customizeHttpClient(httpClientBuilder); } return httpClientBuilder; }; } protected SSLConfigurationCallback.Builder getSSLConfigurationCallbackBuilder() { return SSLConfigurationCallback.Builder.create(); } protected RestClientAuthenticator getCustomAuthenticator(String authClassName, String[] authClassConstructorArgList) { Preconditions.checkArgument(StringUtils.isNotEmpty(authClassName), "Custom authenticator class name cannot be empty"); Preconditions.checkNotNull(authClassConstructorArgList, "Custom authenticator class constructor argument list cannot be null"); final RestClientAuthenticator authenticator; try { final Class c = Class.forName(authClassName); Preconditions.checkArgument(RestClientAuthenticator.class.isAssignableFrom(c), "Authenticator class %s must be a subclass of %s", authClassName, RestClientAuthenticator.class.getName()); @SuppressWarnings("unchecked") final Constructor ctr = ((Class)c).getConstructor(String[].class); authenticator = ctr.newInstance((Object)authClassConstructorArgList); } catch (Exception e) { log.error("Unable to instantiate the custom authenticator {} with constructor arguments \"{}\"", authClassName, authClassConstructorArgList, e); throw new RuntimeException("Unable to instantiate the custom authenticator", e); } try { authenticator.init(); } catch (IOException e) { log.error("Unable to initialize the custom authenticator {} with constructor arguments \"{}\"", authClassName, authClassConstructorArgList, e); throw new RuntimeException("Unable to initialize the custom authenticator", e); } return authenticator; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy