mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Add https support to ES exporter and Sense
Host setting can now specify a protocol + sub path (i.e., https://host:9200/subpath/ ). Custom SSL settings can be configured using `marvel.agent.exporter.es.ssl.*` settings. Those will fall back to Shield `shield.ssl` equivalent settings if found. Sense will now fall back to using https by default if running under https. It will also properly set the withCredentials parameter of XHR to allow for basic auth under CORS setting. Closes #331
This commit is contained in:
parent
a2e20a8777
commit
d7dab15583
7 changed files with 317 additions and 62 deletions
|
@ -50,11 +50,10 @@ import org.elasticsearch.marvel.agent.Utils;
|
|||
import org.elasticsearch.marvel.agent.event.Event;
|
||||
import org.elasticsearch.node.settings.NodeSettingsService;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URL;
|
||||
import java.net.*;
|
||||
import java.security.KeyStore;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -76,10 +75,15 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
volatile int timeoutInMillis;
|
||||
volatile int readTimeoutInMillis;
|
||||
|
||||
|
||||
/** https support * */
|
||||
final SSLSocketFactory sslSocketFactory;
|
||||
|
||||
final ClusterService clusterService;
|
||||
final ClusterName clusterName;
|
||||
HttpServer httpServer;
|
||||
|
||||
|
||||
public final static DateTimeFormatter defaultDatePrinter = Joda.forPattern("date_time").printer();
|
||||
|
||||
volatile boolean checkedAndUploadedIndexTemplate = false;
|
||||
|
@ -91,12 +95,13 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
final ClusterStatsRenderer clusterStatsRenderer;
|
||||
final EventsRenderer eventsRenderer;
|
||||
|
||||
ConnectionKeepAliveWorker keepAliveWorker;
|
||||
final ConnectionKeepAliveWorker keepAliveWorker;
|
||||
Thread keepAliveThread;
|
||||
|
||||
@Inject
|
||||
public ESExporter(Settings settings, ClusterService clusterService, ClusterName clusterName,
|
||||
@ClusterDynamicSettings DynamicSettings dynamicSettings, NodeSettingsService nodeSettingsService) {
|
||||
@ClusterDynamicSettings DynamicSettings dynamicSettings,
|
||||
NodeSettingsService nodeSettingsService) {
|
||||
super(settings);
|
||||
|
||||
this.clusterService = clusterService;
|
||||
|
@ -104,6 +109,17 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
this.clusterName = clusterName;
|
||||
|
||||
hosts = settings.getAsArray(SETTINGS_HOSTS, Strings.EMPTY_ARRAY);
|
||||
|
||||
for (String host : hosts) {
|
||||
try {
|
||||
parseHostWithPath(host, "");
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException("[marvel.agent.exporter] invalid host: [" + host + "]. error: [" + e.getMessage() + "]");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException("[marvel.agent.exporter] invalid host: [" + host + "]. error: [" + e.getMessage() + "]");
|
||||
}
|
||||
}
|
||||
|
||||
indexPrefix = settings.get(SETTINGS_INDEX_PREFIX, ".marvel");
|
||||
String indexTimeFormat = settings.get(SETTINGS_INDEX_TIME_FORMAT, "YYYY.MM.dd");
|
||||
indexTimeFormatter = DateTimeFormat.forPattern(indexTimeFormat).withZoneUTC();
|
||||
|
@ -125,6 +141,14 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
dynamicSettings.addDynamicSetting(SETTINGS_READ_TIMEOUT);
|
||||
nodeSettingsService.addListener(this);
|
||||
|
||||
if (!settings.getByPrefix(SETTINGS_SSL_PREFIX).getAsMap().isEmpty() ||
|
||||
!settings.getByPrefix(SETTINGS_SSL_SHIELD_PREFIX).getAsMap().isEmpty()) {
|
||||
sslSocketFactory = createSSLSocketFactory(settings);
|
||||
} else {
|
||||
logger.trace("no ssl context configured");
|
||||
sslSocketFactory = null;
|
||||
}
|
||||
|
||||
logger.debug("initialized with targets: {}, index prefix [{}], index time format [{}]", hosts, indexPrefix, indexTimeFormat);
|
||||
}
|
||||
|
||||
|
@ -282,7 +306,7 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
|
||||
@Override
|
||||
protected void doStop() {
|
||||
if (keepAliveWorker != null && keepAliveThread.isAlive()) {
|
||||
if (keepAliveThread != null && keepAliveThread.isAlive()) {
|
||||
keepAliveWorker.closed = true;
|
||||
keepAliveThread.interrupt();
|
||||
try {
|
||||
|
@ -352,14 +376,14 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
for (; hostIndex < hosts.length; hostIndex++) {
|
||||
String host = hosts[hostIndex];
|
||||
try {
|
||||
URL url = new URL("http://" + host + "/" + path);
|
||||
if (url.getPort() == -1) {
|
||||
// url has no port, default to 9200
|
||||
host = host + ":9200";
|
||||
url = new URL("http://" + host + "/" + path);
|
||||
}
|
||||
final URL url = parseHostWithPath(host, path);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
if (conn instanceof HttpsURLConnection && sslSocketFactory != null) {
|
||||
HttpsURLConnection httpsConn = (HttpsURLConnection) conn;
|
||||
httpsConn.setSSLSocketFactory(sslSocketFactory);
|
||||
}
|
||||
|
||||
conn.setRequestMethod(method);
|
||||
conn.setConnectTimeout(timeoutInMillis);
|
||||
conn.setReadTimeout(readTimeoutInMillis);
|
||||
|
@ -377,6 +401,8 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
conn.connect();
|
||||
|
||||
return conn;
|
||||
} catch (URISyntaxException e) {
|
||||
logger.error("error parsing host [{}]", e, host);
|
||||
} catch (IOException e) {
|
||||
logger.error("error connecting to [{}]", e, host);
|
||||
}
|
||||
|
@ -397,6 +423,28 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
return null;
|
||||
}
|
||||
|
||||
static URL parseHostWithPath(String host, String path) throws URISyntaxException, MalformedURLException {
|
||||
|
||||
if (!host.contains("://")) {
|
||||
// prefix with http
|
||||
host = "http://" + host;
|
||||
}
|
||||
if (!host.endsWith("/")) {
|
||||
// make sure we can safely resolves sub paths and not replace parent folders
|
||||
host = host + "/";
|
||||
}
|
||||
|
||||
URI hostUrl = new URI(host);
|
||||
|
||||
if (hostUrl.getPort() == -1) {
|
||||
// url has no port, default to 9200
|
||||
hostUrl = new URI(hostUrl.getScheme(), hostUrl.getUserInfo(), hostUrl.getHost(), 9200, hostUrl.getPath(), hostUrl.getQuery(), hostUrl.getFragment());
|
||||
|
||||
}
|
||||
URI hostWithPath = hostUrl.resolve(path);
|
||||
return hostWithPath.toURL();
|
||||
}
|
||||
|
||||
static int parseIndexVersionFromTemplate(byte[] template) throws UnsupportedEncodingException {
|
||||
Pattern versionRegex = Pattern.compile("marvel.index_format\"\\s*:\\s*\"?(\\d+)\"?");
|
||||
Matcher matcher = versionRegex.matcher(new String(template, "UTF-8"));
|
||||
|
@ -777,5 +825,72 @@ public class ESExporter extends AbstractLifecycleComponent<ESExporter> implement
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String SETTINGS_SSL_PREFIX = SETTINGS_PREFIX + "ssl.";
|
||||
private static final String SETTINGS_SSL_SHIELD_PREFIX = "shield.ssl.";
|
||||
|
||||
public static final String SETTINGS_SSL_CONTEXT_ALGORITHM = SETTINGS_SSL_PREFIX + "context_algorithm";
|
||||
private static final String SETTINGS_SSL_SHIELD_CONTEXT_ALGORITHM = SETTINGS_SSL_SHIELD_PREFIX + "context_algorithm";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE = SETTINGS_SSL_PREFIX + "truststore";
|
||||
private static final String SETTINGS_SSL_SHIELD_TRUSTSTORE = SETTINGS_SSL_SHIELD_PREFIX + "truststore";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE_PASSWORD = SETTINGS_SSL_PREFIX + "truststore_password";
|
||||
private static final String SETTINGS_SSL_SHIELD_TRUSTSTORE_PASSWORD = SETTINGS_SSL_SHIELD_PREFIX + "truststore_password";
|
||||
public static final String SETTINGS_SSL_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_PREFIX + "truststore_algorithm";
|
||||
private static final String SETTINGS_SSL_SHIELD_TRUSTSTORE_ALGORITHM = SETTINGS_SSL_SHIELD_PREFIX + "truststore_algorithm";
|
||||
|
||||
|
||||
/** SSL Initialization * */
|
||||
public SSLSocketFactory createSSLSocketFactory(Settings settings) {
|
||||
SSLContext sslContext;
|
||||
// Initialize sslContext
|
||||
try {
|
||||
String sslContextAlgorithm = settings.get(SETTINGS_SSL_CONTEXT_ALGORITHM, settings.get(SETTINGS_SSL_SHIELD_CONTEXT_ALGORITHM, "TLS"));
|
||||
String trustStore = settings.get(SETTINGS_SSL_TRUSTSTORE, settings.get(SETTINGS_SSL_SHIELD_TRUSTSTORE, System.getProperty("javax.net.ssl.trustStore")));
|
||||
String trustStorePassword = settings.get(SETTINGS_SSL_TRUSTSTORE_PASSWORD, settings.get(SETTINGS_SSL_SHIELD_TRUSTSTORE_PASSWORD, System.getProperty("javax.net.ssl.trustStorePassword")));
|
||||
String trustStoreAlgorithm = settings.get(SETTINGS_SSL_TRUSTSTORE_ALGORITHM, settings.get(SETTINGS_SSL_SHIELD_TRUSTSTORE_ALGORITHM, System.getProperty("ssl.TrustManagerFactory.algorithm")));
|
||||
|
||||
if (trustStore == null) {
|
||||
throw new RuntimeException("truststore is not configured, use " + SETTINGS_SSL_TRUSTSTORE);
|
||||
}
|
||||
|
||||
if (trustStoreAlgorithm == null) {
|
||||
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
|
||||
}
|
||||
|
||||
logger.debug("SSL: using trustStore[{}], trustAlgorithm[{}]", trustStore, trustStoreAlgorithm);
|
||||
|
||||
if (!new File(trustStore).exists()) {
|
||||
throw new FileNotFoundException("Truststore at path [" + trustStore + "] does not exist");
|
||||
}
|
||||
|
||||
FileInputStream trustStoreStream = null;
|
||||
TrustManager[] trustManagers;
|
||||
try {
|
||||
trustStoreStream = new FileInputStream(trustStore);
|
||||
// Load TrustStore
|
||||
KeyStore ks = KeyStore.getInstance("jks");
|
||||
ks.load(trustStoreStream, trustStorePassword == null ? null : trustStorePassword.toCharArray());
|
||||
|
||||
// Initialize a trust manager factory with the trusted store
|
||||
TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm);
|
||||
trustFactory.init(ks);
|
||||
|
||||
// Retrieve the trust managers from the factory
|
||||
trustManagers = trustFactory.getTrustManagers();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to initialize a TrustManagerFactory", e);
|
||||
} finally {
|
||||
if (trustStoreStream != null) {
|
||||
trustStoreStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
sslContext = SSLContext.getInstance(sslContextAlgorithm);
|
||||
sslContext.init(null, trustManagers, null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("[marvel.agent.exporter] failed to initialize the SSLContext", e);
|
||||
}
|
||||
return sslContext.getSocketFactory();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
package org.elasticsearch.marvel.agent.exporter;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
|
@ -25,7 +24,6 @@ import org.elasticsearch.cluster.ClusterService;
|
|||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.transport.LocalTransportAddress;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
|
@ -33,14 +31,8 @@ import org.elasticsearch.marvel.agent.event.ClusterEvent;
|
|||
import org.elasticsearch.marvel.agent.event.Event;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
|
||||
|
||||
|
@ -48,18 +40,6 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitC
|
|||
@ClusterScope(transportClientRatio = 0.0, scope = ElasticsearchIntegrationTest.Scope.TEST, numNodes = 0)
|
||||
public class ESExporterTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testVersionIsExtractableFromIndexTemplate() throws IOException {
|
||||
byte[] template;
|
||||
InputStream is = ESExporter.class.getResourceAsStream("/marvel_index_template.json");
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException("Resource [/marvel_index_template.json] not found in classpath");
|
||||
}
|
||||
template = Streams.copyToByteArray(is);
|
||||
is.close();
|
||||
MatcherAssert.assertThat(ESExporter.parseIndexVersionFromTemplate(template), Matchers.greaterThan(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeClusterStateSerialization() throws InterruptedException {
|
||||
// make sure not other exporting is done (quicker)..
|
||||
|
@ -83,6 +63,5 @@ public class ESExporterTests extends ElasticsearchIntegrationTest {
|
|||
ensureYellow();
|
||||
client().admin().indices().prepareRefresh(".marvel-*").get();
|
||||
assertHitCount(client().prepareSearch().setQuery(QueryBuilders.termQuery("event_source", "test_source_unique")).get(), 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* ELASTICSEARCH CONFIDENTIAL
|
||||
* _____________________________
|
||||
*
|
||||
* [2014] Elasticsearch Incorporated All Rights Reserved.
|
||||
*
|
||||
* NOTICE: All information contained herein is, and remains
|
||||
* the property of Elasticsearch Incorporated and its suppliers,
|
||||
* if any. The intellectual and technical concepts contained
|
||||
* herein are proprietary to Elasticsearch Incorporated
|
||||
* and its suppliers and may be covered by U.S. and Foreign Patents,
|
||||
* patents in process, and are protected by trade secret or copyright law.
|
||||
* Dissemination of this information or reproduction of this material
|
||||
* is strictly forbidden unless prior written permission is obtained
|
||||
* from Elasticsearch Incorporated.
|
||||
*/
|
||||
|
||||
|
||||
package org.elasticsearch.marvel.agent.exporter;
|
||||
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
|
||||
public class ESExporterUnitTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testVersionIsExtractableFromIndexTemplate() throws IOException {
|
||||
byte[] template;
|
||||
InputStream is = ESExporter.class.getResourceAsStream("/marvel_index_template.json");
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException("Resource [/marvel_index_template.json] not found in classpath");
|
||||
}
|
||||
template = Streams.copyToByteArray(is);
|
||||
is.close();
|
||||
MatcherAssert.assertThat(ESExporter.parseIndexVersionFromTemplate(template), Matchers.greaterThan(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostParsing() throws MalformedURLException, URISyntaxException {
|
||||
URL url = ESExporter.parseHostWithPath("localhost:9200", "");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/");
|
||||
|
||||
url = ESExporter.parseHostWithPath("localhost", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://localhost:9200", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://localhost", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("https://localhost:9200", "_bulk");
|
||||
verifyUrl(url, "https", "localhost", 9200, "/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("https://boaz-air.local:9200", "_bulk");
|
||||
verifyUrl(url, "https", "boaz-air.local", 9200, "/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("boaz:test@localhost:9200", "");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("boaz:test@localhost", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://boaz:test@localhost:9200", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://boaz:test@localhost", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("https://boaz:test@localhost:9200", "_bulk");
|
||||
verifyUrl(url, "https", "localhost", 9200, "/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("boaz:test@localhost:9200/suburl", "");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/suburl/", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("boaz:test@localhost:9200/suburl/", "");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/suburl/", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("localhost/suburl", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/suburl/_bulk");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://boaz:test@localhost:9200/suburl/suburl1", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/suburl/suburl1/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("http://boaz:test@localhost/suburl", "_bulk");
|
||||
verifyUrl(url, "http", "localhost", 9200, "/suburl/_bulk", "boaz:test");
|
||||
|
||||
url = ESExporter.parseHostWithPath("https://boaz:test@localhost:9200/suburl", "_bulk");
|
||||
verifyUrl(url, "https", "localhost", 9200, "/suburl/_bulk", "boaz:test");
|
||||
}
|
||||
|
||||
void verifyUrl(URL url, String protocol, String host, int port, String path) {
|
||||
assertThat(url.getProtocol(), equalTo(protocol));
|
||||
assertThat(url.getHost(), equalTo(host));
|
||||
assertThat(url.getPort(), equalTo(port));
|
||||
assertThat(url.getPath(), equalTo(path));
|
||||
}
|
||||
|
||||
void verifyUrl(URL url, String protocol, String host, int port, String path, String userInfo) {
|
||||
verifyUrl(url, protocol, host, port, path);
|
||||
assertThat(url.getUserInfo(), equalTo(userInfo));
|
||||
|
||||
}
|
||||
}
|
|
@ -14,7 +14,12 @@ This setting is update-able via the Cluster Update Settings API.
|
|||
+
|
||||
added[1.0.2] - HTTP Basic authentication credentials can be specified as part of the host name,
|
||||
i.e., ["user:pwd@host:9200"]
|
||||
|
||||
+
|
||||
added[1.3.0] - next to the host and port, you can specify a protocol to use,
|
||||
i.e., ["https://host:9200"] (defaults to "http")
|
||||
+
|
||||
added[1.3.0] - the `hostname:port` part can be extended with a base path
|
||||
i.e., ["host:9200/monitor1"]
|
||||
|
||||
`marvel.agent.enabled`::
|
||||
|
||||
|
@ -57,6 +62,20 @@ Enables or disable exporting of shard level statistics. Defaults to `false`.
|
|||
+
|
||||
This setting is update-able via the Cluster Update Settings API.
|
||||
|
||||
==== added[1.3.0] SSL settings when exporting using HTTPS
|
||||
|
||||
`marvel.agent.exporter.es.ssl.truststore`::
|
||||
|
||||
An absolute path for a custom trust store, which will be used for https connections.
|
||||
|
||||
`marvel.agent.exporter.es.ssl.truststore_password`::
|
||||
|
||||
the password to use when accessing the trust store.
|
||||
|
||||
`marvel.agent.exporter.es.ssl.truststore_algorithm`::
|
||||
|
||||
Trust store format (defaults to SunX509).
|
||||
|
||||
|
||||
[[marvel-indices]]
|
||||
=== Marvel indices
|
||||
|
|
|
@ -53,8 +53,7 @@ define([
|
|||
marvelOpts = { status: 'trial' };
|
||||
}
|
||||
|
||||
function submitCurrentRequestToES(cb) {
|
||||
cb = typeof cb === 'function' ? cb : $.noop;
|
||||
function submitCurrentRequestToES() {
|
||||
|
||||
input.getCurrentRequest(function (req) {
|
||||
output.update('');
|
||||
|
@ -72,7 +71,13 @@ define([
|
|||
es_data += "\n";
|
||||
} //append a new line for bulk requests.
|
||||
|
||||
es.send(es_method, es_path, es_data, null, function (xhr, status) {
|
||||
es.send(es_method, es_path, es_data).always(function (dataOrjqXHR, textStatus, jqXhrORerrorThrown) {
|
||||
var xhr;
|
||||
if (dataOrjqXHR.promise) {
|
||||
xhr = dataOrjqXHR;
|
||||
} else {
|
||||
xhr = jqXhrORerrorThrown;
|
||||
}
|
||||
$("#notification").text("").css("visibility", "hidden");
|
||||
if (typeof xhr.status == "number" &&
|
||||
((xhr.status >= 400 && xhr.status < 600) ||
|
||||
|
@ -105,7 +110,7 @@ define([
|
|||
|
||||
}
|
||||
else {
|
||||
cb("Request failed to get to the server (status code: " + xhr.status + "):" + xhr.responseText, 'ace/mode/text');
|
||||
output.update("Request failed to get to the server (status code: " + xhr.status + "):" + xhr.responseText, 'ace/mode/text');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
|
||||
|
||||
define([
|
||||
"_", "jquery", "exports"
|
||||
], function (_, $, exports) {
|
||||
"_", "jquery", "exports"
|
||||
], function (_, $, exports) {
|
||||
"use strict";
|
||||
|
||||
var baseUrl;
|
||||
|
@ -33,7 +33,9 @@ define([
|
|||
return esVersion;
|
||||
};
|
||||
|
||||
exports.send = function (method, path, data, successCallback, completeCallback, server) {
|
||||
exports.send = function (method, path, data, server) {
|
||||
var wrappedDfd = $.Deferred();
|
||||
|
||||
server = server || exports.getBaseUrl();
|
||||
path = exports.constructESUrl(server, path);
|
||||
var uname_password_re = /^(https?:\/\/)?(?:(?:([^\/]*):)?([^\/]*?)@)?(.*)$/;
|
||||
|
@ -50,25 +52,38 @@ define([
|
|||
var options = {
|
||||
url: path,
|
||||
data: method == "GET" ? null : data,
|
||||
password: password,
|
||||
cache: false,
|
||||
username: uname,
|
||||
crossDomain: true,
|
||||
type: method,
|
||||
dataType: "json"
|
||||
password: password,
|
||||
username: uname,
|
||||
dataType: "text" // disable automatic guessing
|
||||
};
|
||||
|
||||
// If we provide callback then apply those to the options otherwise
|
||||
// we assume the user will use the promise interface
|
||||
if (typeof(successCallback) === 'function') {
|
||||
options.success = successCallback;
|
||||
}
|
||||
if (typeof(completeCallback) === 'function') {
|
||||
options.complete= completeCallback;
|
||||
}
|
||||
|
||||
// return the promise that other libraries can use them
|
||||
return $.ajax(options);
|
||||
// first try withCredentials for authentication during preflight checks
|
||||
// sadly it also means Access-Control-Allow-Origin: * is not valid anymore (default
|
||||
// cors setting in ES, when enabled) so we will try again without if needed.
|
||||
$.ajax(_.defaults({},
|
||||
options, {
|
||||
xhrFields: { withCredentials: true} // allow preflight credentials
|
||||
})).then(
|
||||
function (data, textStatus, jqXHR) {
|
||||
wrappedDfd.resolveWith(this, [data, textStatus, jqXHR]);
|
||||
},
|
||||
function (jqXHR, textStatus, errorThrown) {
|
||||
if (jqXHR.status == 0) {
|
||||
$.ajax(options).then(function () { // no withCredentials
|
||||
wrappedDfd.resolveWith(this, arguments);
|
||||
}, function () {
|
||||
wrappedDfd.rejectWith(this, arguments);
|
||||
});
|
||||
}
|
||||
else {
|
||||
wrappedDfd.rejectWith(this, [jqXHR, textStatus, errorThrown])
|
||||
}
|
||||
});
|
||||
return wrappedDfd;
|
||||
};
|
||||
|
||||
exports.constructESUrl = function (server, path) {
|
||||
|
@ -80,7 +95,7 @@ define([
|
|||
return path;
|
||||
}
|
||||
if (server.indexOf("://") < 0) {
|
||||
server = "http://" + server;
|
||||
server = (document.location.protocol || "http:") + "//" + server;
|
||||
}
|
||||
if (server.substr(-1) == "/") {
|
||||
server = server.substr(0, server.length - 1);
|
||||
|
@ -97,7 +112,7 @@ define([
|
|||
if (baseUrl !== base) {
|
||||
var old = baseUrl;
|
||||
baseUrl = base;
|
||||
exports.send("GET", "/", null, null, function (xhr, status) {
|
||||
exports.send("GET", "/").done(function (data, status, xhr) {
|
||||
if (xhr.status === 200) {
|
||||
// parse for version
|
||||
var value = xhr.responseText;
|
||||
|
@ -114,6 +129,11 @@ define([
|
|||
_.each(serverChangeListeners, function (cb) {
|
||||
cb(base, old)
|
||||
});
|
||||
}).fail(function () {
|
||||
esVersion = []; // unknown
|
||||
_.each(serverChangeListeners, function (cb) {
|
||||
cb(base, old)
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -205,9 +205,9 @@ define([
|
|||
}
|
||||
|
||||
function loadAliases(aliases) {
|
||||
per_alias_indexes = {}
|
||||
$.each(aliases, function (index, index_aliases) {
|
||||
$.each(index_aliases.aliases, function (alias) {
|
||||
per_alias_indexes = {};
|
||||
$.each(aliases || {}, function (index, index_aliases) {
|
||||
$.each(index_aliases.aliases || {}, function (alias) {
|
||||
if (alias === index) return; // alias which is identical to index means no index.
|
||||
var cur_aliases = per_alias_indexes[alias];
|
||||
if (!cur_aliases) {
|
||||
|
@ -229,8 +229,8 @@ define([
|
|||
function retrieveMappingFromServer() {
|
||||
$.when(es.send("GET", "_mapping"), es.send("GET", "_aliases"))
|
||||
.done(function (mappings, aliases) {
|
||||
loadMappings(mappings[0]);
|
||||
loadAliases(aliases[0]);
|
||||
loadMappings(JSON.parse(mappings[0]));
|
||||
loadAliases(JSON.parse(aliases[0]));
|
||||
// Trigger an update event with the mappings and aliases
|
||||
$(mappingObj).trigger('update', [mappings[0], aliases[0]]);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue