public static SKU Parse(JsonElement root, ARMFunctions functions, Dictionary <string, object> context) { SKU sku = new SKU(); if (root.TryGetProperty("name", out JsonElement nameE)) { sku.Name = functions.Evaluate(nameE.GetString(), context).ToString(); } else { throw new Exception("cannot find name property in SKU node"); } if (root.TryGetProperty("tier", out JsonElement tierE)) { sku.Name = functions.Evaluate(tierE.GetString(), context).ToString(); } if (root.TryGetProperty("size", out JsonElement sizeE)) { sku.Size = functions.Evaluate(sizeE.GetString(), context).ToString(); } if (root.TryGetProperty("family", out JsonElement familyE)) { sku.Family = functions.Evaluate(familyE.GetString(), context).ToString(); } if (root.TryGetProperty("capacity", out JsonElement capacityE)) { sku.Capacity = capacityE.GetRawText(); } return(sku); }
public void copyindex() { Dictionary <string, object> cxt = new Dictionary <string, object>() { { "currentloopname", "loop1" }, { "copyindex", new Dictionary <string, int>() { { "loop1", 2 }, { "loop2", 7 } } } }; ARMFunctions functions = new ARMFunctions( Options.Create(new ARMOrchestrationOptions()), null, new MockInfrastructure(null)); object rtv = functions.Evaluate("[copyindex()]", cxt); Assert.Equal(2, (int)rtv); rtv = functions.Evaluate("[copyindex(1)]", cxt); Assert.Equal(3, (int)rtv); rtv = functions.Evaluate("[copyindex('loop2')]", cxt); Assert.Equal(7, (int)rtv); rtv = functions.Evaluate("[copyindex('loop2',2)]", cxt); Assert.Equal(9, (int)rtv); }
public static Copy Parse(JsonElement root, Dictionary <string, object> context, ARMFunctions functions, IInfrastructure infrastructure) { var copy = new Copy(); var deployContext = context[ContextKeys.ARM_CONTEXT] as DeploymentContext; if (root.TryGetProperty("name", out JsonElement name)) { copy.Name = name.GetString(); } if (root.TryGetProperty("count", out JsonElement count)) { if (count.ValueKind == JsonValueKind.Number) { copy.Count = count.GetInt32(); } else if (count.ValueKind == JsonValueKind.String) { copy.Count = (int)functions.Evaluate(count.GetString(), context); } else { throw new Exception("the value of count property should be Number in copy node"); } // https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#valid-uses-1 if (context.ContainsKey(ContextKeys.DEPENDSON)) { throw new Exception("You can't use the reference function to set the value of the count property in a copy loop."); } } else { throw new Exception("not find count in copy node"); } if (root.TryGetProperty("mode", out JsonElement mode)) { copy.Mode = mode.GetString().ToLower(); } if (root.TryGetProperty("batchSize", out JsonElement batchSize)) { if (batchSize.ValueKind == JsonValueKind.Number) { copy.BatchSize = batchSize.GetInt32(); } else if (batchSize.ValueKind == JsonValueKind.String) { copy.BatchSize = (int)functions.Evaluate(batchSize.GetString(), context); } } if (root.TryGetProperty("input", out JsonElement input)) { copy.Input = input.GetRawText(); } copy.Id = functions.ResourceId(deployContext, new object[] { $"{infrastructure.BuiltinServiceTypes.Deployments}/{Copy.ServiceType}", deployContext.DeploymentName, copy.Name }); return(copy); }
public void ListResource() { ARMFunctions functions = new ARMFunctions( Options.Create(new ARMOrchestrationOptions()), null, new MockInfrastructure(null)); object rtv = functions.Evaluate( "[listId('resourceId','2019-01-02')]", new Dictionary <string, object>() { { "armcontext", new DeploymentContext() { Template = new Template() } } }); Assert.NotNull(rtv); }
public void ListResourceInPrepareTime() { Dictionary <string, object> cxt = new Dictionary <string, object>() { { "armcontext", new DeploymentContext() { Template = new Template() } }, { ContextKeys.IS_PREPARE, true } }; ARMFunctions functions = new ARMFunctions( Options.Create(new ARMOrchestrationOptions()), null, new MockInfrastructure(null)); object rtv = functions.Evaluate("[listId('resourceId','2019-01-02')]", cxt); Assert.NotNull(rtv); Assert.True(cxt.TryGetValue(ContextKeys.DEPENDSON, out object depend)); var dList = depend as List <string>; Assert.Contains("resourceId", dList); }
public static DeploymentOrchestrationInput Parse(Resource resource, DeploymentContext deploymentContext, ARMFunctions functions, IInfrastructure infrastructure) { var armContext = new Dictionary <string, object>() { { ContextKeys.ARM_CONTEXT, deploymentContext }, { ContextKeys.IS_PREPARE, true } }; using var doc = JsonDocument.Parse(resource.Properties); var rootElement = doc.RootElement; var mode = DeploymentMode.Incremental; if (rootElement.TryGetProperty("mode", out JsonElement _mode)) { if (_mode.GetString().Equals(DeploymentMode.Complete.ToString(), StringComparison.OrdinalIgnoreCase)) { mode = DeploymentMode.Complete; } if (_mode.GetString().Equals(DeploymentMode.OnlyCreation.ToString(), StringComparison.OrdinalIgnoreCase)) { mode = DeploymentMode.OnlyCreation; } } string template = string.Empty; if (rootElement.TryGetProperty("template", out JsonElement _template)) { template = _template.GetRawText(); } TemplateLink templateLink = null; if (rootElement.TryGetProperty("templateLink", out JsonElement _templateLink)) { templateLink = new TemplateLink() { ContentVersion = _templateLink.GetProperty("contentVersion").GetString(), Uri = functions.Evaluate(_templateLink.GetProperty("uri").GetString(), armContext).ToString() }; } // https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/linked-templates#scope-for-expressions-in-nested-templates string parameters = string.Empty; ParametersLink parametersLink = null; if (rootElement.TryGetProperty("expressionEvaluationOptions", out JsonElement _expressionEvaluationOptions) && _expressionEvaluationOptions.GetProperty("scope").GetString().Equals("inner", StringComparison.OrdinalIgnoreCase)) { if (rootElement.TryGetProperty("parameters", out JsonElement _parameters)) { parameters = _parameters.GetRawText(); } if (rootElement.TryGetProperty("parametersLink", out JsonElement _parametersLink)) { parametersLink = new ParametersLink() { ContentVersion = _parametersLink.GetProperty("contentVersion").GetString(), Uri = functions.Evaluate(_parametersLink.GetProperty("uri").GetString(), armContext).ToString() }; } } else { parameters = deploymentContext.Parameters; using MemoryStream ms = new MemoryStream(); using Utf8JsonWriter writer = new Utf8JsonWriter(ms); writer.WriteStartObject(); using var doc1 = JsonDocument.Parse(template); var root1 = doc1.RootElement; foreach (var node in root1.EnumerateObject()) { if (node.Name.Equals("parameters", StringComparison.OrdinalIgnoreCase) || node.Name.Equals("variables", StringComparison.OrdinalIgnoreCase)) { continue; } writer.WritePropertyName(node.Name); node.Value.WriteTo(writer); } if (!string.IsNullOrWhiteSpace(deploymentContext.Template.Parameters)) { using var p = JsonDocument.Parse(deploymentContext.Template.Parameters); writer.WritePropertyName("parameters"); p.RootElement.WriteTo(writer); } if (!string.IsNullOrWhiteSpace(deploymentContext.Template.Variables)) { using var v = JsonDocument.Parse(deploymentContext.Template.Variables); writer.WritePropertyName("variables"); v.RootElement.WriteTo(writer); } writer.WriteEndObject(); writer.Flush(); template = Encoding.UTF8.GetString(ms.ToArray()); } var(groupId, groupType, hierarchyId) = infrastructure.GetGroupInfo(resource.ManagementGroupId, resource.SubscriptionId, resource.ResourceGroup); var deployInput = new DeploymentOrchestrationInput() { RootId = deploymentContext.RootId, DeploymentId = Guid.NewGuid().ToString("N"), ParentId = deploymentContext.GetResourceId(infrastructure), GroupId = groupId, GroupType = groupType, HierarchyId = hierarchyId, CorrelationId = deploymentContext.CorrelationId, SubscriptionId = resource.SubscriptionId, ManagementGroupId = resource.ManagementGroupId, ResourceGroup = resource.ResourceGroup, DeploymentName = resource.Name, Mode = mode, TemplateContent = template, TemplateLink = templateLink, Parameters = parameters, ParametersLink = parametersLink, ApiVersion = resource.ApiVersion, CreateByUserId = deploymentContext.CreateByUserId, LastRunUserId = deploymentContext.LastRunUserId, DependsOn = resource.DependsOn, Extensions = deploymentContext.Extensions, TenantId = deploymentContext.TenantId }; return(Validate(deployInput, functions, infrastructure)); }
private static List <Resource> ParseInternal( JsonElement resourceElement , Dictionary <string, object> context , ARMFunctions functions , IInfrastructure infrastructure , string parentName, string parentType) { DeploymentContext deploymentContext = context[ContextKeys.ARM_CONTEXT] as DeploymentContext; List <Resource> resources = new List <Resource>(); Resource r = new Resource(); resources.Add(r); if (resourceElement.TryGetProperty("condition", out JsonElement condition)) { if (condition.ValueKind == JsonValueKind.False) { r.Condition = false; } else if (condition.ValueKind == JsonValueKind.String) { r.Condition = (bool)functions.Evaluate(condition.GetString(), context); } } if (resourceElement.TryGetProperty("apiVersion", out JsonElement apiVersion)) { r.ApiVersion = apiVersion.GetString(); } else { throw new Exception("not find apiVersion in resource node"); } if (resourceElement.TryGetProperty("type", out JsonElement type)) { r.Type = type.GetString(); } else { throw new Exception("not find type in resource node"); } if (!string.IsNullOrEmpty(parentType)) { r.FullType = $"{parentType}/{r.Type}"; } else { r.FullType = r.Type; } if (resourceElement.TryGetProperty("name", out JsonElement name)) { r.Name = functions.Evaluate(name.GetString(), context).ToString(); } else { throw new Exception("not find name in resource node"); } if (!string.IsNullOrEmpty(parentName)) { r.FullName = $"{parentName}/{r.Name}"; } else { r.FullName = r.Name; } if (resourceElement.TryGetProperty("resourceGroup", out JsonElement resourceGroup)) { r.ResourceGroup = functions.Evaluate(resourceGroup.GetString(), context).ToString(); } else { r.ResourceGroup = deploymentContext.ResourceGroup; } if (resourceElement.TryGetProperty("subscriptionId", out JsonElement subscriptionId)) { r.SubscriptionId = functions.Evaluate(subscriptionId.GetString(), context).ToString(); } else { r.SubscriptionId = deploymentContext.SubscriptionId; } if (resourceElement.TryGetProperty("managementGroupId", out JsonElement managementGroupId)) { r.ManagementGroupId = functions.Evaluate(managementGroupId.GetString(), context).ToString(); } else { r.ManagementGroupId = deploymentContext.ManagementGroupId; } if (resourceElement.TryGetProperty("location", out JsonElement location)) { r.Location = functions.Evaluate(location.GetString(), context).ToString(); } if (resourceElement.TryGetProperty("comments", out JsonElement comments)) { r.Comments = comments.GetString(); } if (resourceElement.TryGetProperty("dependsOn", out JsonElement dependsOn)) { using var dd = JsonDocument.Parse(dependsOn.GetRawText()); foreach (var item in dd.RootElement.EnumerateArray()) { r.DependsOn.Add(functions.Evaluate(item.GetString(), context).ToString()); } } #region ResouceId if (deploymentContext.Template.DeployLevel == DeployLevel.ResourceGroup) { List <object> pars = new List <object> { r.SubscriptionId, r.ResourceGroup, r.FullType }; pars.AddRange(r.FullName.Split('/')); r.ResourceId = functions.ResourceId( deploymentContext, pars.ToArray()); } else if (deploymentContext.Template.DeployLevel == DeployLevel.Subscription) { List <object> pars = new List <object> { r.SubscriptionId, r.FullType }; pars.AddRange(r.FullName.Split('/')); r.ResourceId = functions.SubscriptionResourceId(deploymentContext, pars.ToArray()); } else { List <object> pars = new List <object> { r.FullType }; pars.AddRange(r.FullName.Split('/')); r.ResourceId = functions.TenantResourceId(pars.ToArray()); } #endregion ResouceId if (resourceElement.TryGetProperty("sku", out JsonElement sku)) { r.SKU = SKU.Parse(sku, functions, context); } else { r.SKU = new SKU() { Name = SKU.Default } }; if (resourceElement.TryGetProperty("kind", out JsonElement kind)) { r.Kind = kind.GetString(); } if (resourceElement.TryGetProperty("plan", out JsonElement plan)) { r.Plan = plan.GetRawText(); } if (resourceElement.TryGetProperty("zones", out JsonElement zones)) { foreach (var z in zones.EnumerateArray()) { r.Zones.Add(functions.Evaluate(z.GetString(), context).ToString()); } } if (context.ContainsKey(ContextKeys.DEPENDSON)) { //https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-resource#valid-uses-1 throw new Exception("The reference function can only be used in the properties of a resource definition and the outputs section of a template or deployment."); } if (!r.Condition) { return(resources); } if (resourceElement.TryGetProperty("properties", out JsonElement properties)) { if (r.FullType == infrastructure.BuiltinServiceTypes.Deployments) { r.Properties = properties.GetRawText(); } else { r.Properties = properties.ExpandObject(context, functions, infrastructure); // if there has Implicit dependency by reference function in properties // the reference function should be evaluate at provisioning time // so keep the original text if (HandleDependsOn(r, context)) { r.Properties = properties.GetRawText(); } } } if (resourceElement.TryGetProperty("resources", out JsonElement _resources)) { foreach (var childres in _resources.EnumerateArray()) { //https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/child-resource-name-type var childResult = Resource.Parse(childres.GetRawText(), context, functions, infrastructure, r.Name, r.Type); r.Resources.Add(childResult[0].Name); resources.AddRange(childResult); } } return(resources); }
public static (bool Result, string Message) WriteProperty(this Utf8JsonWriter writer, JsonProperty property, Dictionary <string, object> context, ARMFunctions functions, IInfrastructure infrastructure) { // https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions-numeric#copyindex if ("copy".Equals(property.Name, StringComparison.OrdinalIgnoreCase)) { var copyProperty = property.Value; // this is for Variable and Property iteration if (copyProperty.ValueKind == JsonValueKind.Array) { foreach (var item in property.Value.EnumerateArray()) { Copy copy = null; try { copy = Copy.Parse(item, context, functions, infrastructure); } catch (Exception ex) { return(false, ex.Message); } using JsonDocument doc = JsonDocument.Parse(copy.Input); var copyindex = new Dictionary <string, int>() { { copy.Name, 0 } }; Dictionary <string, object> copyContext = new Dictionary <string, object> { { "copyindex", copyindex }, { "currentloopname", copy.Name } }; foreach (var k in context.Keys) { copyContext.Add(k, context[k]); } writer.WritePropertyName(copy.Name); writer.WriteStartArray(); for (int i = 0; i < copy.Count; i++) { copyindex[copy.Name] = i; writer.WriteElement(doc.RootElement, copyContext, functions, infrastructure); } writer.WriteEndArray(); if (copyContext.TryGetValue(ContextKeys.DEPENDSON, out object copyDependsOn)) { List <string> dependsOn; if (context.TryGetValue(ContextKeys.DEPENDSON, out object d)) { dependsOn = d as List <string>; } else { dependsOn = new List <string>(); context.Add(ContextKeys.DEPENDSON, dependsOn); } dependsOn.AddRange(copyDependsOn as List <string>); } if (copyContext.ContainsKey(ContextKeys.NEED_REEVALUATE)) { context.TryAdd(ContextKeys.NEED_REEVALUATE, true); } } } // this is for output else if (copyProperty.ValueKind == JsonValueKind.Object) { var input = copyProperty.GetProperty("input"); var countProperty = copyProperty.GetProperty("count"); int count; if (countProperty.ValueKind == JsonValueKind.Number) { count = countProperty.GetInt32(); } else if (countProperty.ValueKind == JsonValueKind.String) { count = (int)functions.Evaluate(countProperty.GetString(), context); } else { throw new Exception("the property of count has wrong error. It should be number or an function return a number"); } var name = Guid.NewGuid().ToString("N"); var copyindex = new Dictionary <string, int>() { { name, 0 } }; Dictionary <string, object> copyContext = new Dictionary <string, object> { { "copyindex", copyindex }, { "currentloopname", name } }; foreach (var k in context.Keys) { copyContext.Add(k, context[k]); } writer.WritePropertyName("value"); writer.WriteStartArray(); for (int i = 0; i < count; i++) { copyindex[name] = i; writer.WriteElement(input, copyContext, functions, infrastructure); } writer.WriteEndArray(); } else { throw new Exception("the structer of copy property is wrong"); } } else { writer.WritePropertyName(property.Name); writer.WriteElement(property.Value, context, functions, infrastructure); } return(true, string.Empty); }
public static void WriteElement(this Utf8JsonWriter writer, JsonElement element, Dictionary <string, object> context, ARMFunctions functions, IInfrastructure infrastructure) { switch (element.ValueKind) { case JsonValueKind.Undefined: case JsonValueKind.Number: case JsonValueKind.True: case JsonValueKind.False: case JsonValueKind.Null: element.WriteTo(writer); break; case JsonValueKind.Object: writer.WriteStartObject(); foreach (var p in element.EnumerateObject()) { writer.WriteProperty(p, context, functions, infrastructure); } writer.WriteEndObject(); break; case JsonValueKind.Array: writer.WriteStartArray(); foreach (var a in element.EnumerateArray()) { writer.WriteElement(a, context, functions, infrastructure); } writer.WriteEndArray(); break; case JsonValueKind.String: var r = functions.Evaluate(element.GetString(), context); if (r is JsonValue j) { j.RootElement.WriteTo(writer); } else if (r is bool b) { writer.WriteBooleanValue(b); } else if (r is string s) { writer.WriteStringValue(s); } else if (r is Int32 i) { writer.WriteNumberValue(i); } else if (r is FakeJsonValue) { writer.WriteStringValue("fakeString"); } else { writer.WriteNullValue(); } break; default: break; } }