Implement Azure redis cluster auto config

This commit is contained in:
Warren Zhu 2018-07-09 11:11:13 +08:00
Родитель 30b3946a18
Коммит de8a8f9df2
3 изменённых файлов: 133 добавлений и 11 удалений

Просмотреть файл

@ -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;
}
}

Просмотреть файл

@ -0,0 +1,81 @@
/*
* 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 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("localhost");
assertThat(context.getBean(RedisProperties.class).getPort()).isEqualTo(6379);
assertThat(context.getBean(RedisProperties.class).isSsl()).isTrue();
});
}
@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("localhost");
when(redisCache.nonSslPort()).thenReturn(false);
when(redisCache.sslPort()).thenReturn(6379);
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);
};
}
}