mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-15 23:13:30 +08:00
Allow to configure elasticsearch service with only a URI
Closes gh-789
This commit is contained in:
parent
3b88b952a0
commit
b9000f322d
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,13 @@
|
||||
|
||||
package io.spring.initializr.actuate.stat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.spring.initializr.actuate.stat.StatsProperties.Elastic;
|
||||
import io.spring.initializr.generator.ProjectRequestEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -31,6 +35,7 @@ import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* Publish stats for each project generated to an Elastic index.
|
||||
@ -44,29 +49,25 @@ public class ProjectGenerationStatPublisher {
|
||||
|
||||
private final ProjectRequestDocumentFactory documentFactory;
|
||||
|
||||
private final StatsProperties statsProperties;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private URI requestUrl;
|
||||
|
||||
private final RetryTemplate retryTemplate;
|
||||
|
||||
public ProjectGenerationStatPublisher(ProjectRequestDocumentFactory documentFactory,
|
||||
StatsProperties statsProperties, RestTemplateBuilder restTemplateBuilder,
|
||||
RetryTemplate retryTemplate) {
|
||||
this.documentFactory = documentFactory;
|
||||
this.statsProperties = statsProperties;
|
||||
this.objectMapper = createObjectMapper();
|
||||
StatsProperties.Elastic elastic = statsProperties.getElastic();
|
||||
if (StringUtils.hasText(elastic.getUsername())) {
|
||||
this.restTemplate = restTemplateBuilder
|
||||
.basicAuthentication(elastic.getUsername(), elastic.getPassword())
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
this.restTemplate = restTemplateBuilder.build();
|
||||
}
|
||||
UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
||||
.fromUri(determineEntityUrl(elastic));
|
||||
this.restTemplate = configureAuthorization(restTemplateBuilder, elastic,
|
||||
uriBuilder).build();
|
||||
this.requestUrl = uriBuilder.userInfo(null).build().toUri();
|
||||
this.retryTemplate = retryTemplate;
|
||||
}
|
||||
|
||||
@ -81,8 +82,7 @@ public class ProjectGenerationStatPublisher {
|
||||
}
|
||||
json = toJson(document);
|
||||
|
||||
RequestEntity<String> request = RequestEntity
|
||||
.post(this.statsProperties.getElastic().getEntityUrl())
|
||||
RequestEntity<String> request = RequestEntity.post(this.requestUrl)
|
||||
.contentType(MediaType.APPLICATION_JSON).body(json);
|
||||
|
||||
this.retryTemplate.execute((context) -> {
|
||||
@ -112,8 +112,40 @@ public class ProjectGenerationStatPublisher {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
// For testing purposes only
|
||||
protected RestTemplate getRestTemplate() {
|
||||
return this.restTemplate;
|
||||
}
|
||||
|
||||
protected void updateRequestUrl(URI requestUrl) {
|
||||
this.requestUrl = requestUrl;
|
||||
}
|
||||
|
||||
private static RestTemplateBuilder configureAuthorization(
|
||||
RestTemplateBuilder restTemplateBuilder, Elastic elastic,
|
||||
UriComponentsBuilder uriComponentsBuilder) {
|
||||
String userInfo = uriComponentsBuilder.build().getUserInfo();
|
||||
if (StringUtils.hasText(userInfo)) {
|
||||
String[] credentials = userInfo.split(":");
|
||||
return restTemplateBuilder.basicAuthentication(credentials[0],
|
||||
credentials[1]);
|
||||
}
|
||||
else if (StringUtils.hasText(elastic.getUsername())) {
|
||||
return restTemplateBuilder.basicAuthentication(elastic.getUsername(),
|
||||
elastic.getPassword());
|
||||
}
|
||||
return restTemplateBuilder;
|
||||
}
|
||||
|
||||
private static URI determineEntityUrl(Elastic elastic) {
|
||||
String entityUrl = elastic.getUri() + "/" + elastic.getIndexName() + "/"
|
||||
+ elastic.getEntityName();
|
||||
try {
|
||||
return new URI(entityUrl);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Cannot create entity URL: " + entityUrl, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,9 +16,6 @@
|
||||
|
||||
package io.spring.initializr.actuate.stat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.springframework.util.StringUtils;
|
||||
@ -44,7 +41,7 @@ public class StatsProperties {
|
||||
public static final class Elastic {
|
||||
|
||||
/**
|
||||
* Elastic service uri.
|
||||
* Elastic service uri. Overrides username and password when UserInfo is set.
|
||||
*/
|
||||
private String uri;
|
||||
|
||||
@ -121,17 +118,6 @@ public class StatsProperties {
|
||||
this.uri = cleanUri(uri);
|
||||
}
|
||||
|
||||
public URI getEntityUrl() {
|
||||
String string = this.uri + "/" + this.indexName + "/" + this.entityName;
|
||||
try {
|
||||
return new URI(string);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalStateException("Cannot create entity URL: " + string,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static String cleanUri(String contextPath) {
|
||||
if (StringUtils.hasText(contextPath) && contextPath.endsWith("/")) {
|
||||
return contextPath.substring(0, contextPath.length() - 1);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -54,14 +54,14 @@ public class MainControllerStatsIntegrationTests
|
||||
private StatsMockController statsMockController;
|
||||
|
||||
@Autowired
|
||||
private StatsProperties statsProperties;
|
||||
private ProjectGenerationStatPublisher projectGenerationStatPublisher;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.statsMockController.stats.clear();
|
||||
// Make sure our mock is going to be invoked with the stats
|
||||
this.statsProperties.getElastic()
|
||||
.setUri("http://localhost:" + this.port + "/elastic");
|
||||
this.projectGenerationStatPublisher.updateRequestUrl(
|
||||
URI.create("http://localhost:" + this.port + "/elastic/test/my-entity"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -168,8 +168,8 @@ public class MainControllerStatsIntegrationTests
|
||||
|
||||
@Test
|
||||
public void errorPublishingStatsDoesNotBubbleUp() {
|
||||
this.statsProperties.getElastic()
|
||||
.setUri("http://localhost:" + this.port + "/elastic-error");
|
||||
this.projectGenerationStatPublisher.updateRequestUrl(
|
||||
URI.create("http://localhost:" + this.port + "/elastic-error"));
|
||||
downloadArchive("/starter.zip");
|
||||
assertThat(this.statsMockController.stats).as("No stat should be available")
|
||||
.isEmpty();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -32,13 +32,18 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.test.web.client.RequestMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.header;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.jsonPath;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
|
||||
|
||||
/**
|
||||
* Tests for {@link ProjectGenerationStatPublisher}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests {
|
||||
@ -51,7 +56,10 @@ public class ProjectGenerationStatPublisherTests extends AbstractInitializrStatT
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
StatsProperties properties = createProperties();
|
||||
configureService(createProperties());
|
||||
}
|
||||
|
||||
private void configureService(StatsProperties properties) {
|
||||
ProjectRequestDocumentFactory documentFactory = new ProjectRequestDocumentFactory(
|
||||
createProvider(getMetadata()));
|
||||
this.retryTemplate = new RetryTemplate();
|
||||
@ -62,7 +70,62 @@ public class ProjectGenerationStatPublisherTests extends AbstractInitializrStatT
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishSimpleDocument() {
|
||||
public void publishDocumentWithUserNameAndPassword() {
|
||||
StatsProperties properties = new StatsProperties();
|
||||
properties.getElastic().setUri("http://example.com/elastic");
|
||||
properties.getElastic().setUsername("foo");
|
||||
properties.getElastic().setPassword("bar");
|
||||
configureService(properties);
|
||||
testAuthorization("http://example.com/elastic/initializr/request",
|
||||
header("Authorization", "Basic Zm9vOmJhcg=="));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishDocumentWithUserInfo() {
|
||||
StatsProperties properties = new StatsProperties();
|
||||
properties.getElastic().setUri("https://elastic:secret@es.example.com");
|
||||
configureService(properties);
|
||||
testAuthorization("https://es.example.com/initializr/request",
|
||||
header("Authorization", "Basic ZWxhc3RpYzpzZWNyZXQ="));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishDocumentWithUserInfoOverridesUserNamePassword() {
|
||||
StatsProperties properties = new StatsProperties();
|
||||
properties.getElastic().setUri("https://elastic:secret@es.example.com");
|
||||
properties.getElastic().setUsername("another");
|
||||
properties.getElastic().setPassword("ignored-secret");
|
||||
configureService(properties);
|
||||
testAuthorization("https://es.example.com/initializr/request",
|
||||
header("Authorization", "Basic ZWxhc3RpYzpzZWNyZXQ="));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishDocumentWithNoAuthentication() {
|
||||
StatsProperties properties = new StatsProperties();
|
||||
properties.getElastic().setUri("https://example.com/test/");
|
||||
configureService(properties);
|
||||
testAuthorization("https://example.com/test/initializr/request",
|
||||
(request) -> assertThat(request.getHeaders().containsKey("Authorization"))
|
||||
.isFalse());
|
||||
}
|
||||
|
||||
private void testAuthorization(String expectedUri,
|
||||
RequestMatcher authorizationMatcher) {
|
||||
ProjectRequest request = createProjectRequest();
|
||||
request.setGroupId("com.example.foo");
|
||||
request.setArtifactId("my-project");
|
||||
this.mockServer.expect(requestTo(expectedUri)).andExpect(method(HttpMethod.POST))
|
||||
.andExpect(authorizationMatcher)
|
||||
.andRespond(withStatus(HttpStatus.CREATED)
|
||||
.body(mockResponse(UUID.randomUUID().toString(), true))
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
this.statPublisher.handleEvent(new ProjectGeneratedEvent(request));
|
||||
this.mockServer.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publishDocument() {
|
||||
ProjectRequest request = createProjectRequest();
|
||||
request.setGroupId("com.example.foo");
|
||||
request.setArtifactId("my-project");
|
||||
@ -130,8 +193,6 @@ public class ProjectGenerationStatPublisherTests extends AbstractInitializrStatT
|
||||
StatsProperties properties = new StatsProperties();
|
||||
Elastic elastic = properties.getElastic();
|
||||
elastic.setUri("http://example.com/elastic");
|
||||
elastic.setUsername("foo");
|
||||
elastic.setPassword("bar");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -21,6 +21,8 @@ import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link StatsProperties}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class StatsPropertiesTests {
|
||||
@ -33,13 +35,4 @@ public class StatsPropertiesTests {
|
||||
assertThat(this.properties.getElastic().getUri()).isEqualTo("http://example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void provideEntityUrl() {
|
||||
this.properties.getElastic().setUri("http://example.com/");
|
||||
this.properties.getElastic().setIndexName("my-index");
|
||||
this.properties.getElastic().setEntityName("foo");
|
||||
assertThat(this.properties.getElastic().getEntityUrl().toString())
|
||||
.isEqualTo("http://example.com/my-index/foo");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
initializr:
|
||||
stats:
|
||||
elastic:
|
||||
uri: http://localhost:${server.port}/elastic
|
||||
indexName: test
|
||||
entityName: my-entity
|
||||
uri: http://localhost/elastic
|
||||
username: test-user
|
||||
password: test-password
|
||||
max-attempts: 1
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,8 +28,6 @@ import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* Post-process the environment to extract the service credentials provided by
|
||||
@ -51,16 +49,7 @@ public class CloudfoundryEnvironmentPostProcessor
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
String uri = environment.getProperty("vcap.services.stats-index.credentials.uri");
|
||||
if (StringUtils.hasText(uri)) {
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uri).build();
|
||||
String userInfo = uriComponents.getUserInfo();
|
||||
if (StringUtils.hasText(userInfo)) {
|
||||
String[] credentials = userInfo.split(":");
|
||||
map.put("initializr.stats.elastic.username", credentials[0]);
|
||||
map.put("initializr.stats.elastic.password", credentials[1]);
|
||||
}
|
||||
map.put("initializr.stats.elastic.uri", UriComponentsBuilder
|
||||
.fromUriString(uri).userInfo(null).build().toString());
|
||||
|
||||
map.put("initializr.stats.elastic.uri", uri);
|
||||
addOrReplace(environment.getPropertySources(), map);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -35,21 +35,21 @@ public class CloudfoundryEnvironmentPostProcessorTests {
|
||||
private final SpringApplication application = new SpringApplication();
|
||||
|
||||
@Test
|
||||
public void parseCredentials() {
|
||||
public void parseUriWithCredentials() {
|
||||
this.environment.setProperty("vcap.services.stats-index.credentials.uri",
|
||||
"http://user:pass@example.com/bar/biz?param=one");
|
||||
"https://user:pass@example.com/bar/biz?param=one");
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
|
||||
assertThat(this.environment.getProperty("initializr.stats.elastic.uri"))
|
||||
.isEqualTo("http://example.com/bar/biz?param=one");
|
||||
.isEqualTo("https://user:pass@example.com/bar/biz?param=one");
|
||||
assertThat(this.environment.getProperty("initializr.stats.elastic.username"))
|
||||
.isEqualTo("user");
|
||||
.isNull();
|
||||
assertThat(this.environment.getProperty("initializr.stats.elastic.password"))
|
||||
.isEqualTo("pass");
|
||||
.isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseNoCredentials() {
|
||||
public void parseUri() {
|
||||
this.environment.setProperty("vcap.services.stats-index.credentials.uri",
|
||||
"http://example.com/bar/biz?param=one");
|
||||
this.postProcessor.postProcessEnvironment(this.environment, this.application);
|
||||
|
Loading…
Reference in New Issue
Block a user