Skip to content
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

Extension methods for using programmatic config #1623

Merged
merged 3 commits into from
Mar 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 9 additions & 6 deletions src/Orleans/Serialization/SerializationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ namespace Orleans.Serialization
/// </summary>
public static class SerializationManager
{
internal const string UseFullAssemblyNamesProperty = "UseFullAssemblyNames";
internal const string IndentJsonProperty = "IndentJSON";

/// <summary>
/// Deep copier function.
/// </summary>
Expand Down Expand Up @@ -2320,19 +2323,19 @@ public static JsonSerializerSettings GetDefaultJsonSerializerSettings()
/// <returns><see cref="JsonSerializerSettings" /></returns>
public static JsonSerializerSettings UpdateSerializerSettings(JsonSerializerSettings settings, IProviderConfiguration config)
{
if (config.Properties.ContainsKey("UseFullAssemblyNames"))
if (config.Properties.ContainsKey(UseFullAssemblyNamesProperty))
{
bool useFullAssemblyNames = false;
if (bool.TryParse(config.Properties["UseFullAssemblyNames"], out useFullAssemblyNames) && useFullAssemblyNames)
bool useFullAssemblyNames;
if (bool.TryParse(config.Properties[UseFullAssemblyNamesProperty], out useFullAssemblyNames) && useFullAssemblyNames)
{
settings.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full;
}
}

if (config.Properties.ContainsKey("IndentJSON"))
if (config.Properties.ContainsKey(IndentJsonProperty))
{
bool indentJSON = false;
if (bool.TryParse(config.Properties["IndentJSON"], out indentJSON) && indentJSON)
bool indentJSON;
if (bool.TryParse(config.Properties[IndentJsonProperty], out indentJSON) && indentJSON)
{
settings.Formatting = Formatting.Indented;
}
Expand Down
1 change: 1 addition & 0 deletions src/OrleansAzureUtils/OrleansAzureUtils.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<Compile Include="..\Build\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Providers\AzureConfigurationExtensions.cs" />
<Compile Include="Providers\Storage\AzureBlobStorage.cs" />
<Compile Include="Providers\Streams\PersistentStreams\AzureTableStorageStreamFailureHandler.cs" />
<Compile Include="Providers\Streams\PersistentStreams\StreamDeliveryFailureEntity.cs" />
Expand Down
83 changes: 83 additions & 0 deletions src/OrleansAzureUtils/Providers/AzureConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.Collections.Generic;
using Orleans.Serialization;
using Orleans.Storage;

namespace Orleans.Runtime.Configuration
{
/// <summary>
/// Extension methods for configuration classes specific to OrleansAzureUtils.dll
/// </summary>
public static class AzureConfigurationExtensions
{
/// <summary>
/// Adds a storage provider of type <see cref="Orleans.Storage.AzureTableStorage"/>.
/// </summary>
/// <param name="config">The cluster configuration object to add provider to.</param>
/// <param name="providerName">The provider name</param>
/// <param name="connectionString">The azure storage connection string.</param>
/// <param name="tableName">The table name where to store the state.</param>
/// <param name="deleteOnClear">Whether the provider deletes the state when <see cref="IStorageProvider.ClearStateAsync"/> is called.</param>
/// <param name="useJsonFormat">Whether is stores the content as JSON or as binary in Azure Table.</param>
/// <param name="useFullAssemblyNames">Whether to use full assembly names in the serialized JSON. This value is ignored if <paramref name="useJsonFormat"/> is false.</param>
/// <param name="indentJson">Whether to indent (pretty print) the JSON. This value is ignored if <paramref name="useJsonFormat"/> is false.</param>
public static void AddAzureTableStorageProvider(
this ClusterConfiguration config,
string providerName = "AzureTableStore",
string connectionString = null,
string tableName = AzureTableStorage.TableNamePropertyDefaultValue,
bool deleteOnClear = false,
bool useJsonFormat = false,
bool useFullAssemblyNames = false,
bool indentJson = false)
{
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));

var properties = new Dictionary<string, string>
{
{ AzureTableStorage.DataConnectionStringPropertyName, connectionString },
{ AzureTableStorage.TableNamePropertyName, tableName },
{ AzureTableStorage.DeleteOnClearPropertyName, deleteOnClear.ToString() },
{ AzureTableStorage.UseJsonFormatPropertyName, useJsonFormat.ToString() },
};

if (useJsonFormat)
{
properties.Add(SerializationManager.UseFullAssemblyNamesProperty, useFullAssemblyNames.ToString());
properties.Add(SerializationManager.IndentJsonProperty, indentJson.ToString());
}

config.Globals.RegisterStorageProvider<AzureTableStorage>(providerName, properties);
}

/// <summary>
/// Adds a storage provider of type <see cref="Orleans.Storage.AzureBlobStorage"/>.
/// </summary>
/// <param name="config">The cluster configuration object to add provider to.</param>
/// <param name="providerName">The provider name</param>
/// <param name="connectionString">The azure storage connection string.</param>
/// <param name="containerName">The container name where to store the state.</param>
/// <param name="useFullAssemblyNames">Whether to use full assembly names in the serialized JSON.</param>
/// <param name="indentJson">Whether to indent (pretty print) the JSON.</param>
public static void AddAzureBlobStorageProvider(
this ClusterConfiguration config,
string providerName = "AzureBlobStore",
string connectionString = null,
string containerName = AzureBlobStorage.ContainerNamePropertyDefaultValue,
bool useFullAssemblyNames = false,
bool indentJson = false)
{
if (connectionString == null) throw new ArgumentNullException(nameof(connectionString));

var properties = new Dictionary<string, string>
{
{ AzureBlobStorage.DataConnectionStringPropertyName, connectionString },
{ AzureBlobStorage.ContainerNamePropertyName, containerName },
{ SerializationManager.UseFullAssemblyNamesProperty, useFullAssemblyNames.ToString() },
{ SerializationManager.IndentJsonProperty, indentJson.ToString() },
};

config.Globals.RegisterStorageProvider<AzureBlobStorage>(providerName, properties);
}
}
}
12 changes: 8 additions & 4 deletions src/OrleansAzureUtils/Providers/Storage/AzureBlobStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ namespace Orleans.Storage
/// </example>
public class AzureBlobStorage : IStorageProvider
{
internal const string DataConnectionStringPropertyName = AzureTableStorage.DataConnectionStringPropertyName;
internal const string ContainerNamePropertyName = "ContainerName";
internal const string ContainerNamePropertyDefaultValue = "grainstate";

private JsonSerializerSettings jsonSettings;

private CloudBlobContainer container;
Expand All @@ -67,11 +71,11 @@ public async Task Init(string name, IProviderRuntime providerRuntime, IProviderC
this.Name = name;
this.jsonSettings = SerializationManager.UpdateSerializerSettings(SerializationManager.GetDefaultJsonSerializerSettings(), config);

if (!config.Properties.ContainsKey("DataConnectionString")) throw new BadProviderConfigException("The DataConnectionString setting has not been configured in the cloud role. Please add a DataConnectionString setting with a valid Azure Storage connection string.");
if (!config.Properties.ContainsKey(DataConnectionStringPropertyName)) throw new BadProviderConfigException($"The {DataConnectionStringPropertyName} setting has not been configured in the cloud role. Please add a {DataConnectionStringPropertyName} setting with a valid Azure Storage connection string.");

var account = CloudStorageAccount.Parse(config.Properties["DataConnectionString"]);
var account = CloudStorageAccount.Parse(config.Properties[DataConnectionStringPropertyName]);
var blobClient = account.CreateCloudBlobClient();
var containerName = config.Properties.ContainsKey("ContainerName") ? config.Properties["ContainerName"] : "grainstate";
var containerName = config.Properties.ContainsKey(ContainerNamePropertyName) ? config.Properties[ContainerNamePropertyName] : ContainerNamePropertyDefaultValue;
container = blobClient.GetContainerReference(containerName);
await container.CreateIfNotExistsAsync().ConfigureAwait(false);

Expand All @@ -87,7 +91,7 @@ public async Task Init(string name, IProviderRuntime providerRuntime, IProviderC

IEnumerable<string> FormatPropertyMessage(IProviderConfiguration config)
{
foreach (var property in new string[] { "ContainerName", "SerializeTypeNames", "PreserveReferencesHandling", "UseFullAssemblyNames", "IndentJSON" })
foreach (var property in new string[] { ContainerNamePropertyName, "SerializeTypeNames", "PreserveReferencesHandling", "UseFullAssemblyNames", "IndentJSON" })
{
if (!config.Properties.ContainsKey(property)) continue;
yield return string.Format("{0}={1}", property, config.Properties[property]);
Expand Down
26 changes: 13 additions & 13 deletions src/OrleansAzureUtils/Providers/Storage/AzureTableStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ namespace Orleans.Storage
/// </example>
public class AzureTableStorage : IStorageProvider, IRestExceptionDecoder
{
private const string DATA_CONNECTION_STRING = "DataConnectionString";
private const string TABLE_NAME_PROPERTY = "TableName";
private const string DELETE_ON_CLEAR_PROPERTY = "DeleteStateOnClear";
private const string GRAIN_STATE_TABLE_NAME_DEFAULT = "OrleansGrainState";
internal const string DataConnectionStringPropertyName = "DataConnectionString";
internal const string TableNamePropertyName = "TableName";
internal const string DeleteOnClearPropertyName = "DeleteStateOnClear";
internal const string UseJsonFormatPropertyName = "UseJsonFormat";
internal const string TableNamePropertyDefaultValue = "OrleansGrainState";
private string dataConnectionString;
private string tableName;
private string serviceId;
Expand All @@ -64,7 +65,6 @@ public class AzureTableStorage : IStorageProvider, IRestExceptionDecoder
private const string BINARY_DATA_PROPERTY_NAME = "Data";
private const string STRING_DATA_PROPERTY_NAME = "StringData";

private const string USE_JSON_FORMAT_PROPERTY = "UseJsonFormat";

private bool useJsonFormat;
private Newtonsoft.Json.JsonSerializerSettings jsonSettings;
Expand All @@ -80,7 +80,7 @@ public class AzureTableStorage : IStorageProvider, IRestExceptionDecoder
/// <summary> Default constructor </summary>
public AzureTableStorage()
{
tableName = GRAIN_STATE_TABLE_NAME_DEFAULT;
tableName = TableNamePropertyDefaultValue;
id = Interlocked.Increment(ref counter);
}

Expand All @@ -91,24 +91,24 @@ public Task Init(string name, IProviderRuntime providerRuntime, IProviderConfigu
Name = name;
serviceId = providerRuntime.ServiceId.ToString();

if (!config.Properties.ContainsKey(DATA_CONNECTION_STRING) || string.IsNullOrWhiteSpace(config.Properties[DATA_CONNECTION_STRING]))
if (!config.Properties.ContainsKey(DataConnectionStringPropertyName) || string.IsNullOrWhiteSpace(config.Properties[DataConnectionStringPropertyName]))
throw new ArgumentException("DataConnectionString property not set");

dataConnectionString = config.Properties["DataConnectionString"];

if (config.Properties.ContainsKey(TABLE_NAME_PROPERTY))
tableName = config.Properties[TABLE_NAME_PROPERTY];
if (config.Properties.ContainsKey(TableNamePropertyName))
tableName = config.Properties[TableNamePropertyName];

isDeleteStateOnClear = config.Properties.ContainsKey(DELETE_ON_CLEAR_PROPERTY) &&
"true".Equals(config.Properties[DELETE_ON_CLEAR_PROPERTY], StringComparison.OrdinalIgnoreCase);
isDeleteStateOnClear = config.Properties.ContainsKey(DeleteOnClearPropertyName) &&
"true".Equals(config.Properties[DeleteOnClearPropertyName], StringComparison.OrdinalIgnoreCase);

Log = providerRuntime.GetLogger("Storage.AzureTableStorage." + id);

var initMsg = string.Format("Init: Name={0} ServiceId={1} Table={2} DeleteStateOnClear={3}",
Name, serviceId, tableName, isDeleteStateOnClear);

if (config.Properties.ContainsKey(USE_JSON_FORMAT_PROPERTY))
useJsonFormat = "true".Equals(config.Properties[USE_JSON_FORMAT_PROPERTY], StringComparison.OrdinalIgnoreCase);
if (config.Properties.ContainsKey(UseJsonFormatPropertyName))
useJsonFormat = "true".Equals(config.Properties[UseJsonFormatPropertyName], StringComparison.OrdinalIgnoreCase);

this.jsonSettings = SerializationManager.UpdateSerializerSettings(SerializationManager.GetDefaultJsonSerializerSettings(), config);
initMsg = String.Format("{0} UseJsonFormat={1}", initMsg, useJsonFormat);
Expand Down
32 changes: 32 additions & 0 deletions src/OrleansTestingHost/Extensions/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;

namespace Orleans.Runtime.Configuration
{
public static class ConfigurationExtensions
{
/// <summary>
/// Applies the specified config change defined by <paramref name="nodeConfigUpdater"/> to
/// <see cref="ClusterConfiguration.Defaults"/> and all the node configurations currently
/// defined in <see cref="ClusterConfiguration.Overrides"/>.
/// </summary>
/// <param name="config">The cluster configuration object to add provider to.</param>
/// <param name="nodeConfigUpdater">The function to apply to each node configuration.</param>
public static void ApplyToAllNodes(this ClusterConfiguration config, Action<NodeConfiguration> nodeConfigUpdater)
{
foreach (var nodeConfiguration in config.GetDefinedNodeConfigurations())
{
nodeConfigUpdater.Invoke(nodeConfiguration);
}
}

private static IEnumerable<NodeConfiguration> GetDefinedNodeConfigurations(this ClusterConfiguration config)
{
yield return config.Defaults;
foreach (var nodeConfiguration in config.Overrides.Values)
{
yield return nodeConfiguration;
}
}
}
}
1 change: 1 addition & 0 deletions src/OrleansTestingHost/OrleansTestingHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
<Compile Include="..\Build\GlobalAssemblyInfo.cs">
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Extensions\ConfigurationExtensions.cs" />
<Compile Include="Extensions\TestConfigurationExtensions.cs" />
<Compile Include="OrleansTestSecrets.cs" />
<Compile Include="OrleansTestStorageKey.cs" />
Expand Down
8 changes: 2 additions & 6 deletions test/Tester/GenericGrainsInAzureStorageTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Orleans.Runtime.Configuration;
using Orleans.TestingHost;
using UnitTests.GrainInterfaces;
using UnitTests.Tester;
Expand All @@ -21,11 +21,7 @@ protected override TestingSiloHost CreateClusterHost()
StartSecondary = false,
AdjustConfig = config =>
{
const string myProviderFullTypeName = "Orleans.Storage.AzureTableStorage";
const string myProviderName = "AzureStore";
var properties = new Dictionary<string, string>();
properties.Add("DataConnectionString", "UseDevelopmentStorage=true");
config.Globals.RegisterStorageProvider(myProviderFullTypeName, myProviderName, properties);
config.AddAzureTableStorageProvider("AzureStore", StorageTestConstants.DataConnectionString);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,7 @@ private static void AdjustConfig(ClusterConfiguration config)
{
// register stream provider
config.Globals.RegisterStreamProvider<EventHubStreamProvider>(StreamProviderName, BuildProviderSettings());
config.Globals.RegisterStorageProvider<AzureTableStorage>(
ImplicitSubscription_RecoverableStream_CollectorGrain.StorageProviderName,
new Dictionary<string, string>
{
{"DataConnectionString", StorageTestConstants.DataConnectionString}
});
config.AddAzureTableStorageProvider(ImplicitSubscription_RecoverableStream_CollectorGrain.StorageProviderName, StorageTestConstants.DataConnectionString);

// Make sure a node config exist for each silo in the cluster.
// This is required for the DynamicClusterConfigDeploymentBalancer to properly balance queues.
Expand Down