Родитель
b188b31ebe
Коммит
3a1f3fc71e
|
@ -48,7 +48,7 @@
|
|||
<properties>
|
||||
<azure.adal4j.version>1.3.0</azure.adal4j.version>
|
||||
<azure.documentdb.version>1.13.0</azure.documentdb.version>
|
||||
<azure.storage.version>5.5.0</azure.storage.version>
|
||||
<azure.storage.version>10.1.0</azure.storage.version>
|
||||
<azure.keyvault.version>1.0.0</azure.keyvault.version>
|
||||
<azure.media.version>0.9.7</azure.media.version>
|
||||
<azure.servicebus.version>1.2.5</azure.servicebus.version>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-storage</artifactId>
|
||||
<artifactId>azure-storage-blob</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -120,7 +120,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure</groupId>
|
||||
<artifactId>azure-storage</artifactId>
|
||||
<artifactId>azure-storage-blob</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -6,29 +6,32 @@
|
|||
|
||||
package com.microsoft.azure.spring.autoconfigure.storage;
|
||||
|
||||
import com.microsoft.azure.storage.CloudStorageAccount;
|
||||
import com.microsoft.azure.storage.blob.*;
|
||||
import com.microsoft.azure.telemetry.TelemetryData;
|
||||
import com.microsoft.azure.telemetry.TelemetryProxy;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(CloudStorageAccount.class)
|
||||
@ConditionalOnClass(ServiceURL.class)
|
||||
@EnableConfigurationProperties(StorageProperties.class)
|
||||
@ConditionalOnProperty(prefix = "azure.storage", value = "connection-string")
|
||||
@ConditionalOnProperty(prefix = "azure.storage", value = {"account-name", "account-key"})
|
||||
public class StorageAutoConfiguration {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StorageAutoConfiguration.class);
|
||||
private static final String BLOB_URL = "http://%s.blob.core.windows.net";
|
||||
private static final String USER_AGENT_PREFIX = "spring-storage/";
|
||||
|
||||
private final StorageProperties properties;
|
||||
private final TelemetryProxy telemetryProxy;
|
||||
|
@ -39,26 +42,37 @@ public class StorageAutoConfiguration {
|
|||
}
|
||||
|
||||
/**
|
||||
* Declare CloudStorageAccount bean.
|
||||
*
|
||||
* @return CloudStorageAccount bean
|
||||
* @param options PipelineOptions bean, not required.
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
public CloudStorageAccount cloudStorageAccount() throws URISyntaxException, InvalidKeyException {
|
||||
LOG.debug("cloudStorageAccount called");
|
||||
public ServiceURL createServiceUrl(@Autowired(required = false) PipelineOptions options) throws InvalidKeyException,
|
||||
MalformedURLException {
|
||||
LOG.debug("Creating ServiceURL bean...");
|
||||
trackCustomEvent();
|
||||
return createCloudStorageAccount();
|
||||
|
||||
final SharedKeyCredentials credentials = new SharedKeyCredentials(properties.getAccountName(),
|
||||
properties.getAccountKey());
|
||||
final URL blobUrl = new URL(String.format(BLOB_URL, properties.getAccountName()));
|
||||
final PipelineOptions pipelineOptions = buildOptions(options);
|
||||
final ServiceURL serviceURL = new ServiceURL(blobUrl, StorageURL.createPipeline(credentials, pipelineOptions));
|
||||
|
||||
return serviceURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating CloudStorageAccount instance from storage connection string.
|
||||
*
|
||||
* @return CloudStorageAccount object
|
||||
*/
|
||||
private CloudStorageAccount createCloudStorageAccount() throws URISyntaxException, InvalidKeyException {
|
||||
LOG.debug("createCloudStorageAccount called");
|
||||
return CloudStorageAccount.parse(properties.getConnectionString());
|
||||
private PipelineOptions buildOptions(PipelineOptions fromOptions) {
|
||||
final PipelineOptions pipelineOptions = fromOptions == null ? new PipelineOptions() : fromOptions;
|
||||
|
||||
pipelineOptions.withTelemetryOptions(new TelemetryOptions(USER_AGENT_PREFIX
|
||||
+ pipelineOptions.telemetryOptions().userAgentPrefix()));
|
||||
|
||||
return pipelineOptions;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "azure.storage", value = "container-name")
|
||||
public ContainerURL createContainerURL(ServiceURL serviceURL) {
|
||||
return serviceURL.createContainerURL(properties.getContainerName());
|
||||
}
|
||||
|
||||
private void trackCustomEvent() {
|
||||
|
|
|
@ -3,59 +3,33 @@
|
|||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
package com.microsoft.azure.spring.autoconfigure.storage;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@Validated
|
||||
@ConfigurationProperties("azure.storage")
|
||||
public class StorageProperties {
|
||||
|
||||
/**
|
||||
* Azure Storage connection string.
|
||||
*/
|
||||
@NotEmpty
|
||||
private String connectionString;
|
||||
@Getter
|
||||
@Setter
|
||||
private String accountName;
|
||||
|
||||
@NotEmpty
|
||||
@Getter
|
||||
@Setter
|
||||
private String accountKey;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String containerName;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean allowTelemetry = true;
|
||||
|
||||
/**
|
||||
* return allow telemery or not
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isAllowTelemetry() {
|
||||
return allowTelemetry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allowTelemetry
|
||||
*
|
||||
* @param allowTelemetry
|
||||
*/
|
||||
public void setAllowTelemetry(boolean allowTelemetry) {
|
||||
this.allowTelemetry = allowTelemetry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get storage account connection string.
|
||||
*
|
||||
* @return storage account connection string
|
||||
*/
|
||||
public String getConnectionString() {
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set storage account connection string.
|
||||
*
|
||||
* @param connectionString
|
||||
*/
|
||||
public void setConnectionString(String connectionString) {
|
||||
this.connectionString = connectionString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,54 +5,54 @@
|
|||
*/
|
||||
package com.microsoft.azure.spring.autoconfigure.storage;
|
||||
|
||||
import com.microsoft.azure.storage.CloudStorageAccount;
|
||||
import com.microsoft.azure.storage.blob.ContainerURL;
|
||||
import com.microsoft.azure.storage.blob.ServiceURL;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class StorageAutoConfigurationTest {
|
||||
private static final String CONNECTION_STRING_PROPERTY = "azure.storage.connection-string";
|
||||
private static final String INVALID_CONNECTION_STRING = "invalid connection string";
|
||||
private static final String CONNECTION_STRING_WITH_VALID_FORMAT = "DefaultEndpointsProtocol=https;" +
|
||||
"AccountName=account-name;" +
|
||||
"AccountKey=9ycDniQThM+dT18TmcfhgLyHQCKju9/B9VOtTQ4BOLPhpVbWXbyf9zvNTGe7LB3p2zm5Yl89IQyNgLWw1Wnjxzzj;" +
|
||||
"EndpointSuffix=core.windows.net";
|
||||
private static final String BLOB_URL = "http://%s.blob.core.windows.net";
|
||||
private static final String ACCOUNT_KEY = "ZmFrZUFjY291bnRLZXk="; /* Base64 encoded for string fakeAccountKey */
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(StorageAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
public void createStorageAccountWithInvalidConnectionString() {
|
||||
System.setProperty(CONNECTION_STRING_PROPERTY, INVALID_CONNECTION_STRING);
|
||||
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.register(StorageAutoConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
CloudStorageAccount cloudStorageAccount = null;
|
||||
try {
|
||||
cloudStorageAccount = context.getBean(CloudStorageAccount.class);
|
||||
} catch (Exception e) {
|
||||
assertThat(e).isExactlyInstanceOf(BeanCreationException.class);
|
||||
}
|
||||
|
||||
assertThat(cloudStorageAccount).isNull();
|
||||
}
|
||||
|
||||
System.clearProperty(CONNECTION_STRING_PROPERTY);
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void serviceUrlBeanNotCreatedByDefault() {
|
||||
contextRunner.run(context -> context.getBean(ServiceURL.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createStorageAccountWithValidConnectionStringFormat() {
|
||||
System.setProperty(CONNECTION_STRING_PROPERTY, CONNECTION_STRING_WITH_VALID_FORMAT);
|
||||
public void serviceUrlBeanCreatedCorrectly() {
|
||||
contextRunner.withPropertyValues("azure.storage.account-name=fakeStorageAccountName",
|
||||
"azure.storage.account-key=" + ACCOUNT_KEY)
|
||||
.run(context -> {
|
||||
final ServiceURL serviceURL = context.getBean(ServiceURL.class);
|
||||
final String blobUrl = String.format(BLOB_URL, "fakeStorageAccountName");
|
||||
assertThat(serviceURL).isNotNull();
|
||||
assertThat(serviceURL.toURL().toString()).isEqualTo(blobUrl);
|
||||
});
|
||||
}
|
||||
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.register(StorageAutoConfiguration.class);
|
||||
context.refresh();
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void containerUrlNotCreatedIfNotConfigured() {
|
||||
contextRunner.withPropertyValues("azure.storage.account-name=fakeStorageAccountName",
|
||||
"azure.storage.account-key=" + ACCOUNT_KEY)
|
||||
.run(context -> context.getBean(ContainerURL.class));
|
||||
}
|
||||
|
||||
final CloudStorageAccount cloudStorageAccount = context.getBean(CloudStorageAccount.class);
|
||||
assertThat(cloudStorageAccount).isNotNull();
|
||||
}
|
||||
|
||||
System.clearProperty(CONNECTION_STRING_PROPERTY);
|
||||
@Test
|
||||
public void containerUrlCreatedIfConfigured() {
|
||||
contextRunner.withPropertyValues("azure.storage.account-name=fakeStorageAccountName",
|
||||
"azure.storage.account-key=" + ACCOUNT_KEY,
|
||||
"azure.storage.container-name=fakestoragecontainername")
|
||||
.run(context -> {
|
||||
final ContainerURL containerURL = context.getBean(ContainerURL.class);
|
||||
assertThat(containerURL).isNotNull();
|
||||
assertThat(containerURL.toURL().toString()).contains("fakestoragecontainername");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,77 +5,55 @@
|
|||
*/
|
||||
package com.microsoft.azure.spring.autoconfigure.storage;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBindException;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.validation.BindValidationException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.isA;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class StoragePropertiesTest {
|
||||
private static final String ACCOUNT_NAME_PROP = "azure.storage.account-name";
|
||||
private static final String ACCOUNT_KEY_PROP = "azure.storage.account-key";
|
||||
private static final String CONTAINER_NAME_PROP = "azure.storage.container-name";
|
||||
|
||||
private static final String CONNECTION_STRING = "some connection string";
|
||||
private static final String CONNECTION_STRING_PROPERTY = "azure.storage.connection-string";
|
||||
private static final String ACCOUNT_NAME = "fakeStorageAccountName";
|
||||
private static final String ACCOUNT_KEY = "ZmFrZUFjY291bnRLZXk="; /* Base64 encoded for string fakeAccountKey */
|
||||
private static final String CONTAINER_NAME = "fakestoragecontainername";
|
||||
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(StorageAutoConfiguration.class));
|
||||
@Test
|
||||
public void canSetProperties() {
|
||||
System.setProperty(CONNECTION_STRING_PROPERTY, CONNECTION_STRING);
|
||||
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
|
||||
final StorageProperties properties = context.getBean(StorageProperties.class);
|
||||
assertThat(properties.getConnectionString()).isEqualTo(CONNECTION_STRING);
|
||||
}
|
||||
|
||||
System.clearProperty(CONNECTION_STRING_PROPERTY);
|
||||
contextRunner.withPropertyValues(propValuePair(ACCOUNT_NAME_PROP, ACCOUNT_NAME),
|
||||
propValuePair(ACCOUNT_KEY_PROP, ACCOUNT_KEY), propValuePair(CONTAINER_NAME_PROP, CONTAINER_NAME))
|
||||
.run(context -> {
|
||||
final StorageProperties properties = context.getBean(StorageProperties.class);
|
||||
assertThat(properties.getAccountName()).isEqualTo(ACCOUNT_NAME);
|
||||
assertThat(properties.getAccountKey()).isEqualTo(ACCOUNT_KEY);
|
||||
assertThat(properties.getContainerName()).isEqualTo(CONTAINER_NAME);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptySettingNotAllowed() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
|
||||
Exception exception = null;
|
||||
|
||||
context.register(Config.class);
|
||||
|
||||
try {
|
||||
context.refresh();
|
||||
} catch (Exception e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
assertThat(exception).isNotNull();
|
||||
assertThat(exception).isExactlyInstanceOf(ConfigurationPropertiesBindException.class);
|
||||
|
||||
final BindValidationException bindException = (BindValidationException) exception.getCause().getCause();
|
||||
final List<ObjectError> errors = bindException.getValidationErrors().getAllErrors();
|
||||
final List<String> errorStrings = errors.stream().map(e -> e.toString()).collect(Collectors.toList());
|
||||
|
||||
Collections.sort(errorStrings);
|
||||
|
||||
final List<String> errorStringsExpected = Arrays.asList(
|
||||
"Field error in object 'azure.storage' on field 'connectionString': rejected value [null];"
|
||||
);
|
||||
|
||||
assertThat(errorStrings.size()).isEqualTo(errorStringsExpected.size());
|
||||
|
||||
for (int i = 0; i < errorStrings.size(); i++) {
|
||||
assertThat(errorStrings.get(i)).contains(errorStringsExpected.get(i));
|
||||
}
|
||||
try {
|
||||
contextRunner.withPropertyValues(propValuePair(ACCOUNT_NAME_PROP, ""),
|
||||
propValuePair(ACCOUNT_KEY_PROP, ""))
|
||||
.run(context -> context.getBean(StorageProperties.class));
|
||||
} catch (IllegalStateException e) {
|
||||
assertThat(e.getCause().getCause()).isInstanceOf(ConfigurationPropertiesBindException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(StorageProperties.class)
|
||||
static class Config {
|
||||
private static String propValuePair(String propName, String propValue) {
|
||||
return propName + "=" + propValue;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче