/// <summary> /// Substitutes the property tokens in the supplied string. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="input">The input string.</param> /// <returns>The substituted string</returns> public async Task<string> SubstituteTokensInString(RuntimeContext runtimeContext, TaskContext taskContext, string input) { string output = input; var matches = ImageRegex.Matches(input); if (matches.Count > 0) { foreach (Match match in matches) { string networkDomainId = match.Groups[1].Value; var publicIps = await ListAvailablePublicIps(runtimeContext.AccountDetails, networkDomainId); if (publicIps.Count == 0) { await AddPublicIpBlock(runtimeContext.AccountDetails, networkDomainId); publicIps = await ListAvailablePublicIps(runtimeContext.AccountDetails, networkDomainId); } if (publicIps.Count == 0) { throw new InvalidOperationException("Failed to find free public IP address."); } output = output.Replace(match.Groups[0].Value, publicIps[0]); } } return output; }
/// <summary> /// Substitutes the property tokens in the supplied string. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="input">The input string.</param> /// <returns>The substituted string</returns> public async Task<string> SubstituteTokensInString(RuntimeContext runtimeContext, TaskContext taskContext, string input) { return await Task.Run(() => { return SubstituteTokensInString(input, taskContext.Parameters, true); }); }
/// <summary> /// Runs the orchestration. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="orchestrationObject">The orchestration object.</param> /// <param name="resources">The resources.</param> /// <returns>The async <see cref="Task"/>.</returns> public async Task RunOrchestration(RuntimeContext runtimeContext, TaskContext taskContext, JObject orchestrationObject, IEnumerable<Resource> resources) { _logProvider = runtimeContext.LogProvider; _docsApiClient = new DocsApiClient(orchestrationObject["docsServiceUrl"].Value<string>()); _orchestratorClient = new OrchestratorApiClient(orchestrationObject["orchestratorServiceUrl"].Value<string>()); await Macro.SubstituteTokensInJObject(runtimeContext, taskContext, orchestrationObject); await SendConfiguration((JArray)orchestrationObject["configuration"]); await SendEnvironment((JObject)orchestrationObject["environment"], resources, taskContext.ResourcesProperties); LaunchRunbook(orchestrationObject["runbook"].Value<string>()); }
/// <summary> /// Executes the task. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <returns>The async <see cref="Task"/>.</returns> public async Task Execute(RuntimeContext runtimeContext, TaskContext taskContext) { await Macro.SubstituteTokensInJObject(runtimeContext, taskContext, Resource.ResourceDefinition); var deployer = new ResourceDeployer(runtimeContext, Resource.ResourceId, Resource.ResourceType); var resourceLog = await deployer.DeployAndWait(Resource.ResourceDefinition); taskContext.Log.Resources.Add(resourceLog); taskContext.ResourcesProperties.Add(resourceLog.ResourceId, resourceLog.Details); if (resourceLog.DeploymentStatus == ResourceLogStatus.Failed) { taskContext.Log.Status = DeploymentLogStatus.Failed; } }
public async Task Parameters_SubstituteTokensInString_NotFound() { var context = new TaskContext { Parameters = new Dictionary<string, string>() { { "Param1", "Value1" } } }; var macro = new ParametersMacro(); var input = "Hello_$parameters['Param2']"; await macro.SubstituteTokensInString(null, context, input); }
/// <summary> /// Executes the task. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <returns>The async <see cref="Task"/>.</returns> public async Task Execute(RuntimeContext runtimeContext, TaskContext taskContext) { if (ExistingResources == null) { return; } foreach (var existingResource in ExistingResources) { existingResource.ExistingCaasId = await Macro.SubstituteTokensInString(runtimeContext, taskContext, existingResource.ExistingCaasId); var deployer = new ResourceDeployer(runtimeContext, existingResource.ResourceId, existingResource.ResourceType); var resource = await deployer.Get(existingResource.ExistingCaasId); taskContext.ResourcesProperties.Add(existingResource.ResourceId, resource); } }
/// <summary> /// Executes the task. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <returns>The async <see cref="Task"/>.</returns> public async Task Execute(RuntimeContext runtimeContext, TaskContext taskContext) { if (ResourceLog.CaasId != null) { var deployer = new ResourceDeployer(runtimeContext, ResourceLog.ResourceId, ResourceLog.ResourceType); var resourceLog = await deployer.DeleteAndWait(ResourceLog.CaasId); taskContext.Log.Resources.Add(resourceLog); if (resourceLog.DeploymentStatus == ResourceLogStatus.Failed) { taskContext.Log.Status = DeploymentLogStatus.Failed; } } }
/// <summary> /// Executes the task. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <returns>The async <see cref="Task"/>.</returns> public async Task Execute(RuntimeContext runtimeContext, TaskContext taskContext) { var providerTypeName = Orchestration["provider"].Value<String>(); var providerType = Type.GetType(providerTypeName); if (providerType == null) { runtimeContext.LogProvider.LogError($"Unable to create Orchestration Provider of type {providerTypeName}."); return; } var provider = (IOrchestrationProvider)Activator.CreateInstance(providerType); runtimeContext.LogProvider.LogMessage($"Running Orchestration Provider '{providerTypeName}'."); await provider.RunOrchestration(runtimeContext, taskContext, Orchestration, Resources); }
/// <summary> /// Substitutes the property tokens in the supplied string. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="input">The input string.</param> /// <returns>The substituted string</returns> public static async Task<string> SubstituteTokensInString(RuntimeContext runtimeContext, TaskContext taskContext, string input) { var value = input; if (string.IsNullOrEmpty(value)) { return value; } foreach (var macro in Macros) { value = await macro.SubstituteTokensInString(runtimeContext, taskContext, value); } return value; }
public async Task Parameters_SubstituteTokensInString_Success() { var context = new TaskContext { Parameters = new Dictionary<string, string>() { { "Param1", "Param2" }, { "Param2", "Param3" }, { "Param3", "Param4" } } }; var macro = new ParametersMacro(); var input = "Hello_$parameters[$parameters['Param1']]"; var output = await macro.SubstituteTokensInString(null, context, input); Assert.AreEqual("Hello_Param3", output); }
/// <summary> /// Substitutes the property tokens in the supplied string. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="input">The input string.</param> /// <returns>The substituted string</returns> public async Task<string> SubstituteTokensInString(RuntimeContext runtimeContext, TaskContext taskContext, string input) { string output = input; var matches = ImageRegex.Matches(input); if (matches.Count > 0) { foreach (Match match in matches) { string imageType = match.Groups[1].Value; string location = match.Groups[2].Value; string imageName = match.Groups[3].Value; using (var client = HttpClientFactory.GetClient(runtimeContext.AccountDetails, "text/xml")) { var url = (imageType == "customerImage") ? string.Format(ImageUrl, runtimeContext.AccountDetails.OrgId, imageName) : string.Format(ImageUrl, "base", imageName); var response = await client.GetAsync(runtimeContext.AccountDetails.BaseUrl + url); response.ThrowForHttpFailure(); var responseBody = await response.Content.ReadAsStringAsync(); var document = XDocument.Parse(responseBody); var imageId = document.Root .Elements(ServerNamespace + "image") .Where(e => e.Attribute("location").Value == location) .Select(e => e.Attribute("id").Value) .FirstOrDefault(); if (imageId == null) { throw new TemplateParserException($"Image '{imageName}' not found in datacenter '{location}'."); } output = output.Replace(match.Groups[0].Value, imageId); } } } return output; }
/// <summary> /// Substitutes the tokens in supplied JSON object. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="resourceDefinition">The resource definition.</param> /// <returns>The async <see cref="Task"/>.</returns> public static async Task SubstituteTokensInJObject(RuntimeContext runtimeContext, TaskContext taskContext, JObject resourceDefinition) { foreach (var parameter in resourceDefinition) { if (parameter.Value is JObject) { await SubstituteTokensInJObject(runtimeContext, taskContext, (JObject)parameter.Value); } else if (parameter.Value is JValue) { var value = parameter.Value.Value<string>(); value = await SubstituteTokensInString(runtimeContext, taskContext, value); if (value == string.Empty) { parameter.Value.Replace(null); } else { parameter.Value.Replace(new JValue(value)); } } else if (parameter.Value is JArray) { foreach (var jtoken in ((JArray)parameter.Value)) { if (jtoken is JObject) { await SubstituteTokensInJObject(runtimeContext, taskContext, (JObject)jtoken); } else { var value = jtoken.Value<string>(); value = await SubstituteTokensInString(runtimeContext, taskContext, value); ((JValue)jtoken).Replace(new JValue(value)); } } } } }
/// <summary> /// Substitutes the property tokens in the supplied string. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <param name="input">The input string.</param> /// <returns>The substituted string</returns> public async Task<string> SubstituteTokensInString(RuntimeContext runtimeContext, TaskContext taskContext, string input) { return await Task.Run(() => { string output = input; if (taskContext.ResourcesProperties != null) { MatchCollection resourceMatches = ResourcePropertyRegex.Matches(output); while (resourceMatches.Count > 0) { Match resourceMatch = resourceMatches[resourceMatches.Count - 1]; string resourceId = resourceMatch.Groups[1].Value; string property = resourceMatch.Groups[2].Value; JObject resource; if (!taskContext.ResourcesProperties.TryGetValue(resourceId, out resource)) { throw new TemplateParserException($"Referenced resource '{resourceId}' not found."); } var newValue = resource.SelectToken(property).Value<string>(); if (MacroUtilities.IsNested(output, resourceMatch)) { newValue = "'" + newValue + "'"; } output = output.Replace(resourceMatch.Groups[0].Value, newValue); resourceMatches = ResourcePropertyRegex.Matches(output); } } return output; }); }
/// <summary> /// Gets the deployment tasks for the supplied deployment template. /// </summary> /// <param name="template">The deployment template.</param> /// <param name="scriptPath">The script path.</param> /// <param name="parameters">The deployment parameters.</param> /// <returns>Instance of <see cref="TaskExecutor"/> with tasks and task execution context.</returns> public TaskExecutor BuildTasks(DeploymentTemplate template, string scriptPath, IDictionary<string, string> parameters) { var sortedResources = ResourceDependencies.DependencySort(template.Resources).Reverse().ToList(); // Extract the resources which already exist from the resource collection and create a task to load them. var existingResources = new List<Resource>(); var resourcesWithExistingCaasId = sortedResources .Where(resource => !string.IsNullOrEmpty(resource.ExistingCaasId)) .ToList(); foreach (var resource in resourcesWithExistingCaasId) { var existingCaasId = ParametersMacro.SubstituteTokensInString(resource.ExistingCaasId, parameters, false); if (!string.IsNullOrEmpty(existingCaasId)) { sortedResources.Remove(resource); existingResources.Add(resource); } } var tasks = new List<ITask>(); if (existingResources.Count > 0) { tasks.Add(new LoadExistingResourcesTask(existingResources)); foreach (var existingResource in existingResources) { if ((existingResource.Scripts != null) && (existingResource.ResourceType == ResourceType.Server)) { tasks.Add(new ExecuteScriptTask(existingResource, scriptPath)); } } } // Create the tasks to deploy new resources. foreach (var resource in sortedResources) { tasks.Add(new DeployResourceTask(resource)); if ((resource.Scripts != null) && (resource.ResourceType == ResourceType.Server)) { tasks.Add(new ExecuteScriptTask(resource, scriptPath)); } } if (template.Orchestration != null) { tasks.Add(new RunOrchestrationTask(template.Orchestration, sortedResources)); } if (template.OutputParameters != null && template.OutputParameters.Properties().Any()) { tasks.Add(new SetOutputParametersTask(template.OutputParameters)); } // Create the task execution context. var context = new TaskContext { Parameters = parameters, ResourcesProperties = new Dictionary<string, JObject>(), Log = new DeploymentLog() { DeploymentTime = DateTime.Now, TemplateName = template.Metadata.TemplateName, Resources = new List<ResourceLog>() } }; return new TaskExecutor(template, tasks, context); }
/// <summary> /// Gets the deletion tasks for the supplied deployment log. /// </summary> /// <param name="deploymentLog">The deployment log.</param> /// <returns>Instance of <see cref="TaskExecutor"/> with tasks and task execution context.</returns> public TaskExecutor BuildTasks(DeploymentLog deploymentLog) { // Create a sequential list of tasks we need to execute. var reversedResources = new List<ResourceLog>(deploymentLog.Resources); reversedResources.Reverse(); var tasks = reversedResources .Where(resource => resource.CaasId != null) .Select(resource => (ITask)new DeleteResourceTask(resource)) .ToList(); // Create the task execution context. var context = new TaskContext { Log = new DeploymentLog() { DeploymentTime = DateTime.Now, TemplateName = deploymentLog.TemplateName, Resources = new List<ResourceLog>() } }; return new TaskExecutor(null, tasks, context); }
/// <summary> /// Executes the task. /// </summary> /// <param name="runtimeContext">The runtime context.</param> /// <param name="taskContext">The task execution context.</param> /// <returns>The async <see cref="Task"/>.</returns> public Task Execute(RuntimeContext runtimeContext, TaskContext taskContext) { throw new NotSupportedException("Post-Deploy script not supported."); }