internal static void LogObject(this TestEasyLog log, HostedServiceListResponse.HostedService hostedService) { if (hostedService == null) { return; } if (!string.IsNullOrEmpty(hostedService.ServiceName)) { log.Info(string.Format("HostedService Name:{0}", hostedService.ServiceName)); } log.Info(string.Format("HostedService Url:{0}", hostedService.Uri)); LogObject(log, hostedService.Properties); }
public static async Task DownloadDeploymentAsync(string source, SubscriptionListOperationResponse.Subscription subscription, HostedServiceListResponse.HostedService service, DeploymentSlot slot, StorageAccount temporaryStorage, string downloadToPath, bool warnInsteadOfThrow = false) { Logger.InfoFormat("[" + source + "] " + "Preparing to download {0}/{1}...", service.ServiceName, slot); var computeClient = new ComputeManagementClient(GetCredentials(source, subscription)); var storageClient = new StorageManagementClient(GetCredentials(source, subscription)); Logger.InfoFormat("[" + source + "] " + "Checking existing deployment in {0} slot...", slot); var detailedService = await computeClient.HostedServices.GetDetailedAsync(service.ServiceName); if (!detailedService.Deployments.Where(s => s.DeploymentSlot == slot).Any()) { if (warnInsteadOfThrow) { Logger.WarnFormat("[" + source + "] " + "No deployment found in selected slot, not downloading..."); return; } else { throw new ApplicationException("No deployment found in selected slot"); } } Logger.InfoFormat("[" + source + "] " + "Getting current diagnostics extension data (if any)..."); var detailedSlot = await computeClient.Deployments.GetBySlotAsync(service.ServiceName, slot); string pubConfig = null; if (detailedSlot.ExtensionConfiguration != null) { foreach (var ext in detailedSlot.ExtensionConfiguration.AllRoles.Union(detailedSlot.ExtensionConfiguration.NamedRoles.SelectMany(s => s.Extensions))) { Logger.InfoFormat("[" + source + "] " + "Fetching extension with id {0}...", ext.Id); var extension = await computeClient.HostedServices.GetExtensionAsync(service.ServiceName, ext.Id); if (extension.Type == "PaaSDiagnostics") { Logger.InfoFormat("[" + source + "] " + "Found extension of type {0}, which should be the diagnostics PubConfig...", extension.Type); pubConfig = extension.PublicConfiguration; } } } if (pubConfig == null) { Logger.InfoFormat("[" + source + "] " + "No PaaSDiagnostics extension found..."); } Logger.InfoFormat("[" + source + "] " + "Preparing temp storage account {0}...", temporaryStorage.Name); var keys = await storageClient.StorageAccounts.GetKeysAsync(temporaryStorage.Name); var csa = new CloudStorageAccount(new StorageCredentials(temporaryStorage.Name, keys.PrimaryKey), true); var client = csa.CreateCloudBlobClient(); var container = client.GetContainerReference("acd-temp-" + Guid.NewGuid().ToString("N").ToLower()); Logger.InfoFormat("[" + source + "] " + "Creating temp container {0}...", container.Name); await container.CreateIfNotExistsAsync(); Logger.InfoFormat("[" + source + "] " + "Downloading package to storage account {0}...", temporaryStorage.Name); var getPackageOperation = await computeClient.Deployments.BeginGettingPackageBySlotAsync(service.ServiceName, slot, new DeploymentGetPackageParameters { ContainerUri = container.Uri }); await WaitForOperationAsync(source, subscription, computeClient, getPackageOperation.RequestId); Logger.InfoFormat("[" + source + "] " + "Downloading from storage to {0}...", downloadToPath); var result = await container.ListBlobsSegmentedAsync(null); var prefix = string.Format("{0} {1} {2}", DateTime.Now.ToString("yyyy-MM-dd HH-mm"), service.ServiceName, slot); foreach (var item in result.Results) { var cloudblob = client.GetBlobReferenceFromServer(item.StorageUri); string filename = prefix + " " + cloudblob.Name; Logger.Info("[" + source + "] " + "Downloading: " + filename); await cloudblob.DownloadToFileAsync(Path.Combine(downloadToPath, filename), FileMode.Create); } if (pubConfig != null) { Logger.InfoFormat("[" + source + "] " + "Writing PubConfig to {0}...", prefix + ".PubConfig.xml"); string pubconfigFilename = Path.Combine(downloadToPath, prefix + ".PubConfig.xml"); File.WriteAllText(pubconfigFilename, pubConfig); } Logger.Info("[" + source + "] " + "Cleaning up temp storage..."); await container.DeleteAsync(); Logger.Info("[" + source + "] " + "Package download succesful"); }
private static async Task CleanupExistingExtensions(string source, SubscriptionListOperationResponse.Subscription subscription, HostedServiceListResponse.HostedService service, ComputeManagementClient computeClient, ExtensionImage availableDiagnosticsExtension) { // Get whatever is currently on Production Logger.InfoFormat("[" + source + "] " + "Retrieving current deployment details and currently used extensions..."); DeploymentGetResponse currentProductionSlotDetails = null, currentStagingSlotDetails = null; var details = computeClient.HostedServices.GetDetailed(service.ServiceName); if (details.Deployments.Where(s => s.DeploymentSlot == DeploymentSlot.Production).Any()) { currentProductionSlotDetails = await computeClient.Deployments.GetBySlotAsync(service.ServiceName, DeploymentSlot.Production); } if (details.Deployments.Where(s => s.DeploymentSlot == DeploymentSlot.Staging).Any()) { currentStagingSlotDetails = await computeClient.Deployments.GetBySlotAsync(service.ServiceName, DeploymentSlot.Staging); } // Compile a list of diagnostic id's still in use List <string> diagIdsInUse = new List <string>(); if (currentProductionSlotDetails != null && currentProductionSlotDetails.ExtensionConfiguration != null) { diagIdsInUse.AddRange(currentProductionSlotDetails.ExtensionConfiguration.AllRoles.Select(s => s.Id)); diagIdsInUse.AddRange(currentProductionSlotDetails.ExtensionConfiguration.NamedRoles.SelectMany(s => s.Extensions).Select(s => s.Id)); } if (currentStagingSlotDetails != null && currentStagingSlotDetails.ExtensionConfiguration != null) { diagIdsInUse.AddRange(currentStagingSlotDetails.ExtensionConfiguration.AllRoles.Select(s => s.Id)); diagIdsInUse.AddRange(currentStagingSlotDetails.ExtensionConfiguration.NamedRoles.SelectMany(s => s.Extensions).Select(s => s.Id)); } // Check if diag extension already exists for this service. If so, delete it. Logger.InfoFormat("[" + source + "] " + "Retrieving all extensions for {0}...", service.ServiceName); var currentExtensions = await computeClient.HostedServices.ListExtensionsAsync(service.ServiceName); foreach (var currentDiagExtension in currentExtensions.Where(d => d.Type == availableDiagnosticsExtension.Type)) { if (diagIdsInUse.Contains(currentDiagExtension.Id)) { Logger.InfoFormat("[" + source + "] " + "Skip deleting diagnostics extension {0}, because it is in use by the deployment", currentDiagExtension.Id); } else { Logger.InfoFormat("[" + source + "] " + "Deleting unused diagnostics extension named {0}...", currentDiagExtension.Id); try { var deleteOperation = await computeClient.HostedServices.DeleteExtensionAsync(service.ServiceName, currentDiagExtension.Id); await WaitForOperationAsync(source, subscription, computeClient, deleteOperation.RequestId); } catch (Exception) { Logger.ErrorFormat("[" + source + "] " + "Couldn't delete extension {0}, might be in use...", currentDiagExtension.Id); } } } }
public static async Task DeployAsync(string source, SubscriptionListOperationResponse.Subscription subscription, HostedServiceListResponse.HostedService service, StorageAccount storage, DeploymentSlot slot, UpgradePreference upgradePreference, string pathToCspkg, string pathToCscfg, string pathToDiagExtensionConfig, StorageAccount diagStorage, string deploymentLabel, bool cleanupUnusedExtensions, bool forceWhenUpgrading) { Logger.InfoFormat("[" + source + "] " + "Preparing for deployment of {0}...", service.ServiceName); var credentials = GetCredentials(source, subscription); var computeClient = new ComputeManagementClient(credentials); var storageClient = new StorageManagementClient(credentials); // Load csdef var csCfg = File.ReadAllText(pathToCscfg); // Load diag config var diagConfig = pathToDiagExtensionConfig != null?File.ReadAllText(pathToDiagExtensionConfig) : null; // Upgrade cspkg to storage Logger.InfoFormat("[" + source + "] " + "Fetching key for storage account {0}...", storage.Name); var keys = await storageClient.StorageAccounts.GetKeysAsync(storage.Name); var csa = new CloudStorageAccount(new StorageCredentials(storage.Name, keys.PrimaryKey), true); var blobClient = csa.CreateCloudBlobClient(); var containerRef = blobClient.GetContainerReference("acd-deployments"); if (!await containerRef.ExistsAsync()) { Logger.InfoFormat("[" + source + "] " + "Creating container {0}...", containerRef.Name); await containerRef.CreateIfNotExistsAsync(); } var filename = service.ServiceName + "-" + slot.ToString() + ".cspkg"; var blobRef = containerRef.GetBlockBlobReference(filename); Logger.InfoFormat("[" + source + "] " + "Uploading package to {0}...", blobRef.Uri); await blobRef.UploadFromFileAsync(pathToCspkg, FileMode.Open); // Private diagnostics config string diagStorageName = null, diagStorageKey = null; if (diagStorage == null) { Logger.InfoFormat("[" + source + "] " + "Using storage account credentials from .cscfg for diagnostics..."); Regex regex = new Regex("Diagnostics.ConnectionString.*?DefaultEndpointsProtocol.*?AccountName=(.+?);.*?AccountKey=([a-zA-Z0-9/+=]+)", RegexOptions.Singleline); Match m = regex.Match(csCfg); if (m.Success) { diagStorageName = m.Groups[1].Value; diagStorageKey = m.Groups[2].Value; Logger.InfoFormat("[" + source + "] " + "Extracted storage account {0} from .cscfg for diagnostics...", diagStorageName); } else { throw new ApplicationException("Couldn't extract Diagnostics ConnectionString from .cscfg"); } } else { Logger.InfoFormat("[" + source + "] " + "Using storage account {0} for diagnostics...", diagStorage.Name); if (storage.Name == diagStorage.Name) { diagStorageName = diagStorage.Name; diagStorageKey = keys.PrimaryKey; } else { Logger.InfoFormat("[" + source + "] " + "Fetching keys for storage account {0}...", diagStorage.Name); var diagKeys = await storageClient.StorageAccounts.GetKeysAsync(diagStorage.Name); diagStorageName = diagStorage.Name; diagStorageKey = diagKeys.PrimaryKey; } } var privateDiagConfig = string.Format(@"<PrivateConfig xmlns=""http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration""> <StorageAccount name=""{0}"" key=""{1}"" /> </PrivateConfig>", diagStorageName, diagStorageKey); // Get diagnostics extension template Logger.InfoFormat("[" + source + "] " + "Retrieving available extensions..."); var availableExtensions = await computeClient.HostedServices.ListAvailableExtensionsAsync(); var availableDiagnosticsExtension = availableExtensions.Where(d => d.Type == "PaaSDiagnostics").First(); // Cleanup of existing extensions if (cleanupUnusedExtensions) { await CleanupExistingExtensions(source, subscription, service, computeClient, availableDiagnosticsExtension); } else { Logger.InfoFormat("[" + source + "] " + "Skip cleaning unused extensions as configured"); } // Extensions config var extensionConfiguration = new ExtensionConfiguration(); // Create the extension with new configuration if (diagConfig != null) { var diagnosticsId = "acd-diagnostics-" + Guid.NewGuid().ToString("N"); Logger.InfoFormat("[" + source + "] " + "Adding new diagnostics extension {0}...", diagnosticsId); var createExtensionOperation = await computeClient.HostedServices.BeginAddingExtensionAsync(service.ServiceName, new HostedServiceAddExtensionParameters() { ProviderNamespace = availableDiagnosticsExtension.ProviderNameSpace, Type = availableDiagnosticsExtension.Type, Id = diagnosticsId, Version = availableDiagnosticsExtension.Version, PublicConfiguration = diagConfig, PrivateConfiguration = privateDiagConfig }); await WaitForOperationAsync(source, subscription, computeClient, createExtensionOperation.RequestId); // Extension configuration extensionConfiguration.AllRoles.Add(new ExtensionConfiguration.Extension { Id = diagnosticsId }); } // Create deployment parameters var deployParams = new DeploymentCreateParameters { StartDeployment = true, Name = Guid.NewGuid().ToString("N"), Configuration = csCfg, PackageUri = blobRef.Uri, Label = deploymentLabel ?? DateTime.UtcNow.ToString("u") + " " + Environment.UserName, ExtensionConfiguration = extensionConfiguration }; var upgradeParams = new DeploymentUpgradeParameters { Configuration = csCfg, PackageUri = blobRef.Uri, Label = deploymentLabel ?? DateTime.UtcNow.ToString("u") + " " + Environment.UserName, ExtensionConfiguration = extensionConfiguration, Mode = upgradePreference == UpgradePreference.UpgradeSimultaneously ? DeploymentUpgradeMode.Simultaneous : DeploymentUpgradeMode.Auto, Force = forceWhenUpgrading }; Logger.InfoFormat("[" + source + "] " + "Label for deployment: {0}", deployParams.Label); switch (upgradePreference) { case UpgradePreference.DeleteAndCreateDeploymentInitiallyStopped: case UpgradePreference.DeleteAndCreateDeployment: { // In the case of initially stopped, set StartDeployment to false (we default to 'true' above) if (upgradePreference == UpgradePreference.DeleteAndCreateDeploymentInitiallyStopped) { deployParams.StartDeployment = false; } // Is there a deployment in this slot? Logger.InfoFormat("[" + source + "] " + "Fetching detailed service information..."); var detailedService = await computeClient.HostedServices.GetDetailedAsync(service.ServiceName); var currentDeployment = detailedService.Deployments.Where(s => s.DeploymentSlot == slot).FirstOrDefault(); if (currentDeployment != null) { // Yes, there is. Save the deployment name for the recreate. This is to increase compatibility with // cloud service monitoring tools. deployParams.Name = currentDeployment.Name; // Delete it. Logger.InfoFormat("[" + source + "] " + "Deployment in {0} slot exists, deleting...", slot); var deleteOperation = await computeClient.Deployments.BeginDeletingBySlotAsync(service.ServiceName, slot); await WaitForOperationAsync(source, subscription, computeClient, deleteOperation.RequestId); } // Create a new deployment in this slot Logger.InfoFormat("[" + source + "] " + "Creating deployment in {0} slot...", slot); var createOperation = await computeClient.Deployments.BeginCreatingAsync(service.ServiceName, slot, deployParams); await WaitForOperationAsync(source, subscription, computeClient, createOperation.RequestId); } break; case UpgradePreference.UpgradeWithUpdateDomains: case UpgradePreference.UpgradeSimultaneously: { // Is there a deployment in this slot? Logger.InfoFormat("[" + source + "] " + "Fetching detailed service information..."); var detailedService = await computeClient.HostedServices.GetDetailedAsync(service.ServiceName); var currentDeployment = detailedService.Deployments.Where(s => s.DeploymentSlot == slot).FirstOrDefault(); if (currentDeployment != null) { // Yes, there is. Upgrade it. Logger.InfoFormat("[" + source + "] " + "Deployment in {0} slot exists, upgrading...", slot); var upgradeOperation = await computeClient.Deployments.BeginUpgradingBySlotAsync(service.ServiceName, slot, upgradeParams); await WaitForOperationAsync(source, subscription, computeClient, upgradeOperation.RequestId); } else { // No, there isn't. Create. Logger.InfoFormat("[" + source + "] " + "No deployment in {0} slot yet, creating...", slot); var createOperation = await computeClient.Deployments.BeginCreatingAsync(service.ServiceName, slot, deployParams); await WaitForOperationAsync(source, subscription, computeClient, createOperation.RequestId); } } break; } Logger.InfoFormat("[" + source + "] " + "Deployment succesful"); }