Skip to content

Commit

Permalink
Allow duplicate property assignment and support existing resources (#…
Browse files Browse the repository at this point in the history
…42416)

* Allow duplicate property assignment and support existing resources

* API

* PR fb
  • Loading branch information
JoshLove-msft authored Mar 5, 2024
1 parent 626f940 commit 58d3284
Show file tree
Hide file tree
Showing 16 changed files with 216 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
{
protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func<string, object> createProperties) { }
public Azure.Core.ResourceIdentifier Id { get { throw null; } }
public bool IsExisting { get { throw null; } }
public string Name { get { throw null; } }
public Azure.Provisioning.Resource? Parent { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
Expand Down Expand Up @@ -199,6 +200,7 @@ public partial class KeyVault : Azure.Provisioning.Resource<Azure.ResourceManage
public KeyVault(Azure.Provisioning.IConstruct scope, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultData>)) { }
public void AddAccessPolicy(Azure.Provisioning.Output output) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
public static Azure.Provisioning.KeyVaults.KeyVault FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) { throw null; }
protected override string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
}
public static partial class KeyVaultExtensions
Expand All @@ -208,8 +210,8 @@ public static partial class KeyVaultExtensions
}
public partial class KeyVaultSecret : Azure.Provisioning.Resource<Azure.ResourceManager.KeyVault.KeyVaultSecretData>
{
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ConnectionString connectionString, string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name = "kvs", string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, Azure.Provisioning.KeyVaults.KeyVault? parent = null, string name = "kvs", string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ConnectionString connectionString, Azure.Provisioning.KeyVaults.KeyVault? parent = null, string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
{
protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func<string, object> createProperties) { }
public Azure.Core.ResourceIdentifier Id { get { throw null; } }
public bool IsExisting { get { throw null; } }
public string Name { get { throw null; } }
public Azure.Provisioning.Resource? Parent { get { throw null; } }
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
Expand Down Expand Up @@ -199,6 +200,7 @@ public partial class KeyVault : Azure.Provisioning.Resource<Azure.ResourceManage
public KeyVault(Azure.Provisioning.IConstruct scope, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null, string name = "kv", string version = "2023-02-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultData>)) { }
public void AddAccessPolicy(Azure.Provisioning.Output output) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
public static Azure.Provisioning.KeyVaults.KeyVault FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) { throw null; }
protected override string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
}
public static partial class KeyVaultExtensions
Expand All @@ -208,8 +210,8 @@ public static partial class KeyVaultExtensions
}
public partial class KeyVaultSecret : Azure.Provisioning.Resource<Azure.ResourceManager.KeyVault.KeyVaultSecretData>
{
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ConnectionString connectionString, string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name = "kvs", string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, Azure.Provisioning.KeyVaults.KeyVault? parent = null, string name = "kvs", string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
public KeyVaultSecret(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ConnectionString connectionString, Azure.Provisioning.KeyVaults.KeyVault? parent = null, string version = "2023-02-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func<string, Azure.ResourceManager.KeyVault.KeyVaultSecretData>)) { }
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
}
}
Expand Down
2 changes: 1 addition & 1 deletion sdk/provisioning/Azure.Provisioning/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "net",
"TagPrefix": "net/provisioning/Azure.Provisioning",
"Tag": "net/provisioning/Azure.Provisioning_be6662616d"
"Tag": "net/provisioning/Azure.Provisioning_15c6f021fe"
}
10 changes: 7 additions & 3 deletions sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,15 @@ public BinaryData SerializeModule()

foreach (var resource in GetResources(false))
{
if (resource.IsExisting)
{
continue;
}
if (resource is Tenant)
{
continue;
}
if (resource is ResourceGroup && resource.Id.Name == "resourceGroup()")
if (resource is ResourceGroup && resource.Id.Name == ResourceGroup.ResourceGroupFunction)
{
continue;
}
Expand All @@ -139,11 +143,11 @@ public BinaryData SerializeModule()

private void WriteExistingResources(MemoryStream stream)
{
foreach (var resource in GetExistingResources(false))
foreach (var resource in GetResources(false).Where(r => r.IsExisting))
{
stream.WriteLine();
stream.WriteLine($"resource {resource.Name} '{resource.Id.ResourceType}@{resource.Version}' existing = {{");
stream.WriteLine($" name: '{resource.Name}'");
stream.WriteLine($" name: '{resource.Id.Name}'");
stream.WriteLine($"}}");
}
}
Expand Down
26 changes: 15 additions & 11 deletions sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,25 +112,29 @@ private void BuildModuleConstructs(Resource resource, Dictionary<Resource, List<

if (parentScope != null)
{
foreach (var parameter in resource.Parameters)
foreach (var parameter in resource.Scope.GetParameters(false))
{
parentScope.AddParameter(parameter);
}

foreach (var typeDictPair in resource.ParameterOverrides)
foreach (var typeDictPair in resource.PropertyOverrides)
{
// ToList to avoid modifying the collection while iterating
foreach (var propertyParameterPair in typeDictPair.Value.ToList())
{
var parameterToCopy = propertyParameterPair.Value;
resource.ParameterOverrides[typeDictPair.Key][propertyParameterPair.Key] = new Parameter(
parameterToCopy.Name,
parameterToCopy.Description,
parameterToCopy.DefaultValue,
parameterToCopy.IsSecure,
var parameterToCopy = propertyParameterPair.Value.Parameter;
if (parameterToCopy == null)
{
continue;
}
resource.PropertyOverrides[typeDictPair.Key][propertyParameterPair.Key] = new PropertyOverride(parameter: new Parameter(
parameterToCopy.Value.Name,
parameterToCopy.Value.Description,
parameterToCopy.Value.DefaultValue,
parameterToCopy.Value.IsSecure,
parentScope,
parameterToCopy.Value,
parameterToCopy.Output);
parameterToCopy.Value.Value,
parameterToCopy.Value.Output));
}
}
}
Expand Down Expand Up @@ -164,7 +168,7 @@ private bool NeedsModuleConstruct(Resource resource, Dictionary<Resource, List<R
}
}

if (resource is ResourceGroup)
if (resource is ResourceGroup && !resource.IsExisting)
{
// TODO add policy support
return resourceTree[resource].Count > 0;
Expand Down
16 changes: 16 additions & 0 deletions sdk/provisioning/Azure.Provisioning/src/PropertyOverride.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

namespace Azure.Provisioning
{
internal struct PropertyOverride
{
public string? PropertyValue { get; }
public Parameter? Parameter { get; }
internal PropertyOverride(string? propertyValue = default, Parameter? parameter = default)
{
PropertyValue = propertyValue;
Parameter = parameter;
}
}
}
42 changes: 21 additions & 21 deletions sdk/provisioning/Azure.Provisioning/src/Resource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ namespace Azure.Provisioning
public abstract class Resource : IPersistableModel<Resource>
#pragma warning restore AZC0012 // Avoid single word type names
{
internal Dictionary<object, Dictionary<string, Parameter>> ParameterOverrides { get; }

private Dictionary<object, Dictionary<string, string>> PropertyOverrides { get; }
internal Dictionary<object, Dictionary<string, PropertyOverride>> PropertyOverrides { get; }

private IList<Resource> Dependencies { get; }

Expand Down Expand Up @@ -74,20 +72,26 @@ internal void AddDependency(Resource resource)
/// <param name="createProperties">Lambda to create the ARM properties.</param>
/// <exception cref="ArgumentNullException">If <paramref name="scope"/> is null.</exception>
protected Resource(IConstruct scope, Resource? parent, string resourceName, ResourceType resourceType, string version, Func<string, object> createProperties)
: this(scope, parent, resourceName, resourceType, version, createProperties, false)
{
}

internal Resource(IConstruct scope, Resource? parent, string resourceName, ResourceType resourceType, string version, Func<string, object> createProperties, bool isExisting)
{
if (scope is null) throw new ArgumentNullException(nameof(scope));

Scope = scope;
Parameters = new List<Parameter>();
Parent = parent ?? FindParentInScope(scope);
var azureName = GetAzureName(scope, resourceName);

var azureName = isExisting ? resourceName : GetAzureName(scope, resourceName);
Scope.AddResource(this);
ResourceData = createProperties(azureName);
Version = version;
ParameterOverrides = new Dictionary<object, Dictionary<string, Parameter>>();
PropertyOverrides = new Dictionary<object, Dictionary<string, string>>();
PropertyOverrides = new Dictionary<object, Dictionary<string, PropertyOverride>>();
Dependencies = new List<Resource>();
ResourceType = resourceType;
IsExisting = isExisting;
Id = Parent is null
? ResourceIdentifier.Root
: Parent is ResourceGroup
Expand All @@ -96,6 +100,11 @@ protected Resource(IConstruct scope, Resource? parent, string resourceName, Reso
Name = GetHash();
}

/// <summary>
/// Whether or not the resource already exists.
/// </summary>
public bool IsExisting { get; }

/// <summary>
/// Validate and sanitize the resource name.
/// </summary>
Expand Down Expand Up @@ -161,13 +170,13 @@ protected string GetGloballyUniqueName(string resourceName)
/// <param name="parameter">The <see cref="Parameter"/> to assign.</param>
private protected void AssignProperty(object instance, string propertyName, Parameter parameter)
{
if (ParameterOverrides.TryGetValue(instance, out var overrides))
if (PropertyOverrides.TryGetValue(instance, out var overrides))
{
overrides[propertyName] = parameter;
overrides[propertyName] = new PropertyOverride(parameter: parameter);
}
else
{
ParameterOverrides.Add(instance, new Dictionary<string, Parameter> { { propertyName, parameter } });
PropertyOverrides.Add(instance, new Dictionary<string, PropertyOverride> { { propertyName, new PropertyOverride(parameter: parameter) } });
}
Scope.AddParameter(parameter);
//TODO: We should not need this instead a parameter should have a reference to the resource it is associated with but belong to the construct only.
Expand All @@ -179,11 +188,11 @@ private protected void AssignProperty(object instance, string propertyName, stri
{
if (PropertyOverrides.TryGetValue(instance, out var overrides))
{
overrides[propertyName] = propertyValue;
overrides[propertyName] = new PropertyOverride(propertyValue: propertyValue);
}
else
{
PropertyOverrides.Add(instance, new Dictionary<string, string> { { propertyName, propertyValue } });
PropertyOverrides.Add(instance, new Dictionary<string, PropertyOverride> { { propertyName, new PropertyOverride(propertyValue: propertyValue) } });
}
}

Expand Down Expand Up @@ -262,15 +271,6 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options)
}

var bicepOptions = new BicepModelReaderWriterOptions();
foreach (var parameter in ParameterOverrides)
{
var dict = new Dictionary<string, string>();
foreach (var kvp in parameter.Value)
{
dict.Add(kvp.Key, kvp.Value.GetParameterString(ModuleScope!));
}
bicepOptions.ParameterOverrides.Add(parameter.Key, dict);
}
foreach (var propertyOverride in PropertyOverrides)
{
if (!bicepOptions.ParameterOverrides.TryGetValue(propertyOverride.Key, out var dict))
Expand All @@ -280,7 +280,7 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options)
}
foreach (var kvp in propertyOverride.Value)
{
dict.Add(kvp.Key, kvp.Value);
dict[kvp.Key] = kvp.Value.Parameter?.GetParameterString(ModuleScope!) ?? kvp.Value.PropertyValue;
}
}
var data = ModelReaderWriter.Write(ResourceData, bicepOptions).ToMemory();
Expand Down
Loading

0 comments on commit 58d3284

Please sign in to comment.