-
Notifications
You must be signed in to change notification settings - Fork 41.2k
Add support for Elasticsearch Sniffer #24340
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
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.time.Duration; | ||
import java.time.temporal.TemporalUnit; | ||
|
||
import org.apache.http.HttpHost; | ||
import org.apache.http.auth.AuthScope; | ||
|
@@ -31,13 +32,16 @@ | |
import org.elasticsearch.client.RestClientBuilder; | ||
import org.elasticsearch.client.RestHighLevelClient; | ||
|
||
import org.elasticsearch.client.sniff.Sniffer; | ||
import org.elasticsearch.client.sniff.SnifferBuilder; | ||
import org.springframework.beans.factory.ObjectProvider; | ||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.boot.context.properties.PropertyMapper; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Conditional; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.util.StringUtils; | ||
|
||
|
@@ -80,6 +84,19 @@ RestClientBuilder elasticsearchRestClientBuilder(ElasticsearchRestClientProperti | |
return builder; | ||
} | ||
|
||
@Bean | ||
@Conditional(IsSnifferAvailableOnClasspathCondition.class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's not how classpath checks work. Can you please have a look to |
||
@ConditionalOnMissingBean(RestHighLevelClient.class) | ||
Sniffer elasticsearchSnifferBuilder(ElasticsearchRestClientProperties properties, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
RestClient elasticSearchRestClient) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have you run the test before pushing an update? As I've explained several times in this issue, we do not expose a RestClient so requiring a RestClient bean is never going to work. |
||
return Sniffer.builder(elasticSearchRestClient) | ||
.setSniffIntervalMillis( | ||
Math.toIntExact(properties.getSniffInterval().toMillis())) | ||
.setSniffAfterFailureDelayMillis( | ||
Math.toIntExact(properties.getSniffFailureDelay().toMillis())) | ||
.build(); | ||
} | ||
|
||
private HttpHost createHttpHost(String uri) { | ||
try { | ||
return createHttpHost(URI.create(uri)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,14 @@ public class ElasticsearchRestClientProperties { | |
* Read timeout. | ||
*/ | ||
private Duration readTimeout = Duration.ofSeconds(30); | ||
/** | ||
* Sniffer interval | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Configuration property description ends with a dot. Please consider reviewing the description to better explain what that does. |
||
*/ | ||
private Duration sniffInterval = Duration.ofMinutes(5L); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those properties should be in a |
||
/** | ||
* Sniffer failure delay. | ||
*/ | ||
private Duration sniffFailureDelay = Duration.ofMinutes(1L); | ||
|
||
public List<String> getUris() { | ||
return this.uris; | ||
|
@@ -97,4 +105,19 @@ public void setReadTimeout(Duration readTimeout) { | |
this.readTimeout = readTimeout; | ||
} | ||
|
||
public Duration getSniffInterval() { | ||
return sniffInterval; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing |
||
} | ||
|
||
public void setSniffInterval(Duration sniffInterval) { | ||
this.sniffInterval = sniffInterval; | ||
} | ||
|
||
public Duration getSniffFailureDelay() { | ||
return sniffFailureDelay; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
} | ||
|
||
public void setSniffFailureDelay(Duration sniffFailureDelay) { | ||
this.sniffFailureDelay = sniffFailureDelay; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package org.springframework.boot.autoconfigure.elasticsearch; | ||
|
||
import org.springframework.context.annotation.Condition; | ||
import org.springframework.context.annotation.ConditionContext; | ||
import org.springframework.core.type.AnnotatedTypeMetadata; | ||
|
||
public class IsSnifferAvailableOnClasspathCondition implements Condition { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should go away. |
||
@Override | ||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { | ||
return isSnifferJarOnClasspath(); | ||
} | ||
private boolean isSnifferJarOnClasspath() | ||
{ | ||
try { | ||
Class.forName("org.elasticsearch.client.sniff.Sniffer"); | ||
return true; | ||
} catch (ClassNotFoundException e) { | ||
return false; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,8 +16,10 @@ | |
|
||
package org.springframework.boot.autoconfigure.elasticsearch; | ||
|
||
import java.io.IOException; | ||
import java.time.Duration; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.apache.http.HttpHost; | ||
|
@@ -34,6 +36,10 @@ | |
import org.elasticsearch.client.RestClient; | ||
import org.elasticsearch.client.RestClientBuilder; | ||
import org.elasticsearch.client.RestHighLevelClient; | ||
import org.elasticsearch.client.sniff.NodesSniffer; | ||
import org.elasticsearch.client.sniff.Sniffer; | ||
import org.elasticsearch.client.sniff.SnifferBuilder; | ||
import org.junit.Assert; | ||
import org.junit.jupiter.api.Test; | ||
import org.testcontainers.elasticsearch.ElasticsearchContainer; | ||
import org.testcontainers.junit.jupiter.Container; | ||
|
@@ -220,6 +226,51 @@ void configureUriWithUsernameAndPasswordWhenUsernameAndPasswordPropertiesSet() { | |
}); | ||
} | ||
|
||
@Test | ||
void configureShouldOnlyCreateSnifferInstance() { | ||
this.contextRunner.run( | ||
(context) -> assertThat(context).doesNotHaveBean(RestClient.class) | ||
.hasSingleBean(RestHighLevelClient.class)); | ||
this.contextRunner.run( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A single test shouldn't run the context twice ideally. |
||
(context) -> assertThat(context).hasSingleBean(Sniffer.class)); | ||
} | ||
|
||
@Test | ||
void configureShouldHaveSnifferInstance() { | ||
this.contextRunner.run( | ||
(context) -> assertThat(context).doesNotHaveBean(RestClient.class) | ||
.hasSingleBean(RestHighLevelClient.class)); | ||
this.contextRunner.run( | ||
(context) -> { | ||
assertThat(context).hasSingleBean(Sniffer.class); | ||
Assert.assertNotNull(context.getBean(Sniffer.class)); | ||
}); | ||
} | ||
|
||
@Test | ||
void configureWithCustomSetIntervalProperties() { | ||
this.contextRunner.withPropertyValues("spring.elasticsearch.rest.sniffInterval=15s, " + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"spring.elasticsearch.rest.sniffFailureDelay=15s").run((context) -> { | ||
Assert.assertNotNull(context.getBean(Sniffer.class)); | ||
}); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two tests are missing here. One that assert what happens when the library is not on the classpath, as I've indicated in my previous review. One that assert that a custom |
||
@Test | ||
void configureWithNoAutoConfigurationPropertySet() { | ||
this.contextRunner.run((context) -> { | ||
assertThat(context).doesNotHaveBean(Sniffer.class); | ||
Assert.assertNull(context.getBean(Sniffer.class)); | ||
}); | ||
} | ||
|
||
@Test | ||
void configureWhenCustomSnifferWhenPresent() { | ||
this.contextRunner.withBean("customSniffer", Sniffer.class, () -> mock(Sniffer.class)) | ||
.run((context) -> assertThat(context).hasSingleBean(RestHighLevelClient.class) | ||
.hasSingleBean(Sniffer.class).hasBean("customSniffer")); | ||
} | ||
|
||
|
||
@Configuration(proxyBeanMethods = false) | ||
static class BuilderCustomizerConfiguration { | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.