Last active
August 8, 2017 04:23
-
-
Save sjwaight/984dff1eb48c55eac46ef3c1aec0f1a2 to your computer and use it in GitHub Desktop.
Sample startup code showing how we can configure a VMSS instance based on its hostname and role.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace MyDemo.Website.WebApi | |
{ | |
public class WebApiApplication : System.Web.HttpApplication | |
{ | |
// This value is used if for some reason the configuration doesn't have a defined | |
// application insights instrumentation key | |
private const string DefaultAppInsightsKey = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; | |
// Yes, these are hardcoded - need to change? Recompile and build VM Image and redeploy. | |
private const string ConfigurationDbId = "apiconfigs"; | |
private const string ConfigurationDbCollection = "apiconfigentries"; | |
private const string ServiceIdentifier = "webapi"; | |
private static Dictionary<string, string> instanceTelemetry; | |
internal static string LoggingDatabaseCollection; | |
internal static string LoggingDatabaseKey; | |
internal static string LoggingDatabase; | |
internal static string LoggingDatabaseCollection; | |
internal static string ConfigDatabaseAccount; | |
internal static string ConfigDatabaseKey; | |
protected void Application_Start() | |
{ | |
ApplyConfiguration(); | |
// removed other initialisation code | |
} | |
private void ApplyConfiguration() | |
{ | |
// Assumes you correctly version your assemblies... you do, don't you? :) | |
instanceTelemetry = new Dictionary<string, string> | |
{ | |
{ "Version", Assembly.GetExecutingAssembly().GetName().Version.ToString() }, | |
{ "Hostname", Environment.MachineName } | |
}; | |
// Assumption that VM is an instance in an Azure VM Scale Set where | |
// instance names end with a 6 character hexatrigesimal value to uniquely identify them. | |
var instanceKey = Environment.MachineName.Substring(0, Environment.MachineName.Length - 6); // strip last 6 characters | |
// Secret URI in keyvault that will contain config DB information. | |
// Yes, the KeyVault instance is hardcoded which requires the solution to be re-compiled and re-deployed if | |
// changed. This is on purpose to stop people editing configuration on running instances. They | |
// should be editing the source code and pushing through the CD pipeline to re-bake the VM image. | |
var configDbSecretUri = $"https://yourkeyvaultinstance.vault.azure.net/secrets/{instanceKey}-{ServiceIdentifier}-configdb-account/"; | |
var configDbKeySecretUri = $"https://yourkeyvaultinstance.vault.azure.net/secrets/{instanceKey}-{ServiceIdentifier}-configdb-key/"; | |
// Call Key Vault and retrieve secret. | |
// Uses an Azure AD Service Principal to access | |
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(KevVaultUtils.GetToken)); | |
// Configuration DB account and key read from KeyVault. | |
ConfigDatabaseAccount = keyVaultClient.GetSecretAsync(configDbSecretUri).Result.Value; | |
ConfigDatabaseKey = keyVaultClient.GetSecretAsync(configDbKeySecretUri).Result.Value; | |
var configResult = new ApiConfiguration(); | |
try | |
{ | |
// DocumentDbClient is just a helper class that provides a singleton client class I can use. | |
configResult = DocumentDbClient.ConfigInstance.CreateDocumentQuery<ApiConfiguration>( | |
UriFactory.CreateDocumentCollectionUri(ConfigurationDbId, ConfigurationDbCollection), new FeedOptions { MaxItemCount = 1 }) | |
.Where(ac => ac.Id == $"{instanceKey}-{ServiceIdentifier}" && ac.AccessKey == ConfigDatabaseKey).AsEnumerable().FirstOrDefault(); | |
if (!string.IsNullOrWhiteSpace(configResult.Id)) | |
{ | |
// Default fallback App Insights instance list above. | |
// This means even if we have a misconfiguration we should get telemetry *somewhere* | |
TelemetryConfiguration.Active.InstrumentationKey = string.IsNullOrWhiteSpace(configResult.AppInsightsKey) ? DefaultAppInsightsKey : configResult.AppInsightsKey; | |
// Our runtime values that can be used by our code | |
LoggingDatabaseAccount = configResult.LoggingDatabaseAccount; | |
LoggingDatabaseKey = configResult.LoggingDatabaseKey; | |
LoggingDatabase = configResult.LoggingDatabase; | |
LoggingDatabaseCollection = configResult.LoggingDatabaseCollection; | |
} | |
else | |
{ | |
throw new ConfigurationErrorsException("Service is not configured correctly."); | |
} | |
} | |
catch (Exception ex) | |
{ | |
AppInsightsClient.ClientInstance.TrackException(ex, instanceTelemetry); | |
// Bubble Exception | |
throw; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment