Merge pull request #56 from Microsoft/refactor
Implement azure redis cluster auto config
This commit is contained in:
Коммит
2c87e6eaa5
|
@ -12,6 +12,7 @@ import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoCo
|
|||
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureProperties;
|
||||
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryTracker;
|
||||
import com.microsoft.azure.spring.cloud.autoconfigure.telemetry.TelemetryUtils;
|
||||
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
|
@ -26,6 +27,7 @@ import org.springframework.context.annotation.Primary;
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* An auto-configuration for Spring cache using Azure redis cache
|
||||
|
@ -48,26 +50,32 @@ public class AzureRedisAutoConfiguration {
|
|||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Primary
|
||||
@Bean
|
||||
public RedisProperties redisProperties(Azure azure, AzureProperties azureProperties,
|
||||
AzureRedisProperties azureRedisProperties) throws IOException {
|
||||
public RedisProperties redisProperties(AzureAdmin azureAdmin,
|
||||
AzureRedisProperties azureRedisProperties) throws IOException {
|
||||
String cacheName = azureRedisProperties.getName();
|
||||
|
||||
RedisCache redisCache = azure.redisCaches()
|
||||
.getByResourceGroup(azureProperties.getResourceGroup(), cacheName);
|
||||
RedisCache redisCache = azureAdmin.getOrCreateRedisCache(cacheName);
|
||||
|
||||
RedisProperties redisProperties = new RedisProperties();
|
||||
redisProperties.setHost(redisCache.hostName());
|
||||
redisProperties.setPassword(redisCache.getKeys().primaryKey());
|
||||
|
||||
boolean useSsl = !redisCache.nonSslPort();
|
||||
int port = useSsl ? redisCache.sslPort() : redisCache.port();
|
||||
|
||||
redisProperties.setPort(useSsl ? redisCache.sslPort() : redisCache.port());
|
||||
boolean isCluster = redisCache.shardCount() > 0;
|
||||
|
||||
if (isCluster) {
|
||||
RedisProperties.Cluster cluster = new RedisProperties.Cluster();
|
||||
cluster.setNodes(Arrays.asList(redisCache.hostName() + ":" + port));
|
||||
redisProperties.setCluster(cluster);
|
||||
} else {
|
||||
redisProperties.setHost(redisCache.hostName());
|
||||
redisProperties.setPort(port);
|
||||
}
|
||||
|
||||
redisProperties.setPassword(redisCache.getKeys().primaryKey());
|
||||
redisProperties.setSsl(useSsl);
|
||||
|
||||
// TODO: handle cluster related config, Azure redis management api unsupported
|
||||
|
||||
return redisProperties;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,16 @@
|
|||
|
||||
package com.microsoft.azure.spring.cloud.autoconfigure.cache;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Warren Zhu
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties("spring.cloud.azure.redis")
|
||||
public class AzureRedisProperties {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,20 +6,16 @@
|
|||
|
||||
package com.microsoft.azure.spring.cloud.autoconfigure.eventhub;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Warren Zhu
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties("spring.cloud.azure.eventhub")
|
||||
public class AzureEventHubProperties {
|
||||
private String namespace;
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = namespace;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
package com.microsoft.azure.spring.cloud.autoconfigure.sql;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
|
@ -13,6 +15,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
|||
*
|
||||
* @author Warren Zhu
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties("spring.cloud.azure.sql")
|
||||
public class AzureSqlProperties {
|
||||
|
||||
|
|
|
@ -6,20 +6,16 @@
|
|||
|
||||
package com.microsoft.azure.spring.cloud.autoconfigure.storage;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Warren Zhu
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties("spring.cloud.azure.storage")
|
||||
public class AzureStorageProperties {
|
||||
private String account;
|
||||
|
||||
public String getAccount() {
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public void setAccount(String account) {
|
||||
this.account = account;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See LICENSE in the project root for
|
||||
* license information.
|
||||
*/
|
||||
|
||||
package com.microsoft.azure.spring.cloud.autoconfigure.cache;
|
||||
|
||||
import com.microsoft.azure.management.Azure;
|
||||
import com.microsoft.azure.management.redis.RedisAccessKeys;
|
||||
import com.microsoft.azure.management.redis.RedisCache;
|
||||
import com.microsoft.azure.spring.cloud.autoconfigure.context.AzureContextAutoConfiguration;
|
||||
import com.microsoft.azure.spring.cloud.context.core.AzureAdmin;
|
||||
import com.microsoft.azure.spring.cloud.context.core.CredentialsProvider;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class AzureRedisAutoConfigurationTest {
|
||||
private static final String KEY = "KEY";
|
||||
private static final String HOST = "localhost";
|
||||
private static final int PORT = 6379;
|
||||
private static final boolean IS_SSL = true;
|
||||
private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(AzureContextAutoConfiguration.class, AzureRedisAutoConfiguration.class))
|
||||
.withUserConfiguration(
|
||||
TestConfiguration.class);
|
||||
|
||||
@Test
|
||||
public void testWithoutAzureRedisProperties() {
|
||||
this.contextRunner.run(context -> assertThat(context).doesNotHaveBean(AzureRedisProperties.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAzureRedisPropertiesConfigured() {
|
||||
this.contextRunner.withPropertyValues("spring.cloud.azure.redis.name=redis").run(context -> {
|
||||
assertThat(context).hasSingleBean(AzureRedisProperties.class);
|
||||
assertThat(context.getBean(AzureRedisProperties.class).getName()).isEqualTo("redis");
|
||||
assertThat(context).hasSingleBean(RedisProperties.class);
|
||||
assertThat(context.getBean(RedisProperties.class).getPassword()).isEqualTo(KEY);
|
||||
assertThat(context.getBean(RedisProperties.class).getHost()).isEqualTo(HOST);
|
||||
assertThat(context.getBean(RedisProperties.class).getPort()).isEqualTo(PORT);
|
||||
assertThat(context.getBean(RedisProperties.class).isSsl()).isEqualTo(IS_SSL);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean
|
||||
public CredentialsProvider credentialsProvider() {
|
||||
return mock(CredentialsProvider.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
Azure azure() {
|
||||
return mock(Azure.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
AzureAdmin azureAdmin() {
|
||||
|
||||
AzureAdmin azureAdmin = mock(AzureAdmin.class);
|
||||
RedisCache redisCache = mock(RedisCache.class);
|
||||
RedisAccessKeys accessKeys = mock(RedisAccessKeys.class);
|
||||
when(accessKeys.primaryKey()).thenReturn(KEY);
|
||||
when(redisCache.hostName()).thenReturn(HOST);
|
||||
when(redisCache.nonSslPort()).thenReturn(!IS_SSL);
|
||||
when(redisCache.sslPort()).thenReturn(PORT);
|
||||
when(redisCache.shardCount()).thenReturn(0);
|
||||
when(redisCache.getKeys()).thenReturn(accessKeys);
|
||||
when(azureAdmin.getOrCreateRedisCache(isA(String.class))).thenReturn(redisCache);
|
||||
return azureAdmin;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ package com.microsoft.azure.spring.cloud.context.core;
|
|||
import com.microsoft.azure.management.Azure;
|
||||
import com.microsoft.azure.management.eventhub.EventHub;
|
||||
import com.microsoft.azure.management.eventhub.EventHubNamespace;
|
||||
import com.microsoft.azure.management.redis.RedisCache;
|
||||
import com.microsoft.azure.management.servicebus.Queue;
|
||||
import com.microsoft.azure.management.servicebus.ServiceBusNamespace;
|
||||
import com.microsoft.azure.management.servicebus.ServiceBusSubscription;
|
||||
|
@ -17,6 +18,8 @@ import com.microsoft.azure.management.sql.SqlServer;
|
|||
import com.microsoft.azure.management.storage.StorageAccount;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class AzureAdmin {
|
||||
|
||||
private final Azure azure;
|
||||
|
@ -144,7 +147,13 @@ public class AzureAdmin {
|
|||
}
|
||||
|
||||
public ServiceBusNamespace getServiceBusNamespace(String namespace) {
|
||||
return azure.serviceBusNamespaces().getByResourceGroup(resourceGroup, namespace);
|
||||
try {
|
||||
return azure.serviceBusNamespaces().getByResourceGroup(resourceGroup, namespace);
|
||||
} catch (NullPointerException ignore) {
|
||||
// azure management api has no way to determine whether an service bus namespace exists
|
||||
// Workaround for this is by catching NPE
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ServiceBusNamespace createServiceBusNamespace(String namespace) {
|
||||
|
@ -206,4 +215,28 @@ public class AzureAdmin {
|
|||
return topic.subscriptions().define(name).create();
|
||||
}
|
||||
|
||||
public RedisCache getRedisCache(String name) {
|
||||
return azure.redisCaches().getByResourceGroup(resourceGroup, name);
|
||||
}
|
||||
|
||||
public RedisCache createRedisCache(String name) {
|
||||
return azure.redisCaches().define(name).withRegion(region).withExistingResourceGroup(resourceGroup)
|
||||
.withBasicSku().create();
|
||||
}
|
||||
|
||||
public RedisCache getOrCreateRedisCache(String name) {
|
||||
return getOrCreate(this::getRedisCache, this::createRedisCache).apply(name);
|
||||
}
|
||||
|
||||
private <T, R> Function<T, R> getOrCreate(Function<T, R> getter, Function<T, R> creator) {
|
||||
return t -> {
|
||||
R result = getter.apply(t);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return creator.apply(t);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче