Skip to content

Commit 58d3284

Browse files
Allow duplicate property assignment and support existing resources (#42416)
* Allow duplicate property assignment and support existing resources * API * PR fb
1 parent 626f940 commit 58d3284

File tree

16 files changed

+216
-63
lines changed

16 files changed

+216
-63
lines changed

sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net6.0.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
9191
{
9292
protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func<string, object> createProperties) { }
9393
public Azure.Core.ResourceIdentifier Id { get { throw null; } }
94+
public bool IsExisting { get { throw null; } }
9495
public string Name { get { throw null; } }
9596
public Azure.Provisioning.Resource? Parent { get { throw null; } }
9697
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
@@ -199,6 +200,7 @@ public partial class KeyVault : Azure.Provisioning.Resource<Azure.ResourceManage
199200
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>)) { }
200201
public void AddAccessPolicy(Azure.Provisioning.Output output) { }
201202
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
203+
public static Azure.Provisioning.KeyVaults.KeyVault FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) { throw null; }
202204
protected override string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
203205
}
204206
public static partial class KeyVaultExtensions
@@ -208,8 +210,8 @@ public static partial class KeyVaultExtensions
208210
}
209211
public partial class KeyVaultSecret : Azure.Provisioning.Resource<Azure.ResourceManager.KeyVault.KeyVaultSecretData>
210212
{
211-
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>)) { }
212-
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>)) { }
213+
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>)) { }
214+
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>)) { }
213215
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
214216
}
215217
}

sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.netstandard2.0.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public abstract partial class Resource : System.ClientModel.Primitives.IPersista
9191
{
9292
protected Resource(Azure.Provisioning.IConstruct scope, Azure.Provisioning.Resource? parent, string resourceName, Azure.Core.ResourceType resourceType, string version, System.Func<string, object> createProperties) { }
9393
public Azure.Core.ResourceIdentifier Id { get { throw null; } }
94+
public bool IsExisting { get { throw null; } }
9495
public string Name { get { throw null; } }
9596
public Azure.Provisioning.Resource? Parent { get { throw null; } }
9697
public Azure.Provisioning.IConstruct Scope { get { throw null; } }
@@ -199,6 +200,7 @@ public partial class KeyVault : Azure.Provisioning.Resource<Azure.ResourceManage
199200
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>)) { }
200201
public void AddAccessPolicy(Azure.Provisioning.Output output) { }
201202
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
203+
public static Azure.Provisioning.KeyVaults.KeyVault FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) { throw null; }
202204
protected override string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; }
203205
}
204206
public static partial class KeyVaultExtensions
@@ -208,8 +210,8 @@ public static partial class KeyVaultExtensions
208210
}
209211
public partial class KeyVaultSecret : Azure.Provisioning.Resource<Azure.ResourceManager.KeyVault.KeyVaultSecretData>
210212
{
211-
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>)) { }
212-
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>)) { }
213+
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>)) { }
214+
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>)) { }
213215
protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; }
214216
}
215217
}

sdk/provisioning/Azure.Provisioning/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "net",
44
"TagPrefix": "net/provisioning/Azure.Provisioning",
5-
"Tag": "net/provisioning/Azure.Provisioning_be6662616d"
5+
"Tag": "net/provisioning/Azure.Provisioning_15c6f021fe"
66
}

sdk/provisioning/Azure.Provisioning/src/ModuleConstruct.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,15 @@ public BinaryData SerializeModule()
113113

114114
foreach (var resource in GetResources(false))
115115
{
116+
if (resource.IsExisting)
117+
{
118+
continue;
119+
}
116120
if (resource is Tenant)
117121
{
118122
continue;
119123
}
120-
if (resource is ResourceGroup && resource.Id.Name == "resourceGroup()")
124+
if (resource is ResourceGroup && resource.Id.Name == ResourceGroup.ResourceGroupFunction)
121125
{
122126
continue;
123127
}
@@ -139,11 +143,11 @@ public BinaryData SerializeModule()
139143

140144
private void WriteExistingResources(MemoryStream stream)
141145
{
142-
foreach (var resource in GetExistingResources(false))
146+
foreach (var resource in GetResources(false).Where(r => r.IsExisting))
143147
{
144148
stream.WriteLine();
145149
stream.WriteLine($"resource {resource.Name} '{resource.Id.ResourceType}@{resource.Version}' existing = {{");
146-
stream.WriteLine($" name: '{resource.Name}'");
150+
stream.WriteLine($" name: '{resource.Id.Name}'");
147151
stream.WriteLine($"}}");
148152
}
149153
}

sdk/provisioning/Azure.Provisioning/src/ModuleInfrastructure.cs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,25 +112,29 @@ private void BuildModuleConstructs(Resource resource, Dictionary<Resource, List<
112112

113113
if (parentScope != null)
114114
{
115-
foreach (var parameter in resource.Parameters)
115+
foreach (var parameter in resource.Scope.GetParameters(false))
116116
{
117117
parentScope.AddParameter(parameter);
118118
}
119119

120-
foreach (var typeDictPair in resource.ParameterOverrides)
120+
foreach (var typeDictPair in resource.PropertyOverrides)
121121
{
122122
// ToList to avoid modifying the collection while iterating
123123
foreach (var propertyParameterPair in typeDictPair.Value.ToList())
124124
{
125-
var parameterToCopy = propertyParameterPair.Value;
126-
resource.ParameterOverrides[typeDictPair.Key][propertyParameterPair.Key] = new Parameter(
127-
parameterToCopy.Name,
128-
parameterToCopy.Description,
129-
parameterToCopy.DefaultValue,
130-
parameterToCopy.IsSecure,
125+
var parameterToCopy = propertyParameterPair.Value.Parameter;
126+
if (parameterToCopy == null)
127+
{
128+
continue;
129+
}
130+
resource.PropertyOverrides[typeDictPair.Key][propertyParameterPair.Key] = new PropertyOverride(parameter: new Parameter(
131+
parameterToCopy.Value.Name,
132+
parameterToCopy.Value.Description,
133+
parameterToCopy.Value.DefaultValue,
134+
parameterToCopy.Value.IsSecure,
131135
parentScope,
132-
parameterToCopy.Value,
133-
parameterToCopy.Output);
136+
parameterToCopy.Value.Value,
137+
parameterToCopy.Value.Output));
134138
}
135139
}
136140
}
@@ -164,7 +168,7 @@ private bool NeedsModuleConstruct(Resource resource, Dictionary<Resource, List<R
164168
}
165169
}
166170

167-
if (resource is ResourceGroup)
171+
if (resource is ResourceGroup && !resource.IsExisting)
168172
{
169173
// TODO add policy support
170174
return resourceTree[resource].Count > 0;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
namespace Azure.Provisioning
5+
{
6+
internal struct PropertyOverride
7+
{
8+
public string? PropertyValue { get; }
9+
public Parameter? Parameter { get; }
10+
internal PropertyOverride(string? propertyValue = default, Parameter? parameter = default)
11+
{
12+
PropertyValue = propertyValue;
13+
Parameter = parameter;
14+
}
15+
}
16+
}

sdk/provisioning/Azure.Provisioning/src/Resource.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@ namespace Azure.Provisioning
2121
public abstract class Resource : IPersistableModel<Resource>
2222
#pragma warning restore AZC0012 // Avoid single word type names
2323
{
24-
internal Dictionary<object, Dictionary<string, Parameter>> ParameterOverrides { get; }
25-
26-
private Dictionary<object, Dictionary<string, string>> PropertyOverrides { get; }
24+
internal Dictionary<object, Dictionary<string, PropertyOverride>> PropertyOverrides { get; }
2725

2826
private IList<Resource> Dependencies { get; }
2927

@@ -74,20 +72,26 @@ internal void AddDependency(Resource resource)
7472
/// <param name="createProperties">Lambda to create the ARM properties.</param>
7573
/// <exception cref="ArgumentNullException">If <paramref name="scope"/> is null.</exception>
7674
protected Resource(IConstruct scope, Resource? parent, string resourceName, ResourceType resourceType, string version, Func<string, object> createProperties)
75+
: this(scope, parent, resourceName, resourceType, version, createProperties, false)
76+
{
77+
}
78+
79+
internal Resource(IConstruct scope, Resource? parent, string resourceName, ResourceType resourceType, string version, Func<string, object> createProperties, bool isExisting)
7780
{
7881
if (scope is null) throw new ArgumentNullException(nameof(scope));
7982

8083
Scope = scope;
8184
Parameters = new List<Parameter>();
8285
Parent = parent ?? FindParentInScope(scope);
83-
var azureName = GetAzureName(scope, resourceName);
86+
87+
var azureName = isExisting ? resourceName : GetAzureName(scope, resourceName);
8488
Scope.AddResource(this);
8589
ResourceData = createProperties(azureName);
8690
Version = version;
87-
ParameterOverrides = new Dictionary<object, Dictionary<string, Parameter>>();
88-
PropertyOverrides = new Dictionary<object, Dictionary<string, string>>();
91+
PropertyOverrides = new Dictionary<object, Dictionary<string, PropertyOverride>>();
8992
Dependencies = new List<Resource>();
9093
ResourceType = resourceType;
94+
IsExisting = isExisting;
9195
Id = Parent is null
9296
? ResourceIdentifier.Root
9397
: Parent is ResourceGroup
@@ -96,6 +100,11 @@ protected Resource(IConstruct scope, Resource? parent, string resourceName, Reso
96100
Name = GetHash();
97101
}
98102

103+
/// <summary>
104+
/// Whether or not the resource already exists.
105+
/// </summary>
106+
public bool IsExisting { get; }
107+
99108
/// <summary>
100109
/// Validate and sanitize the resource name.
101110
/// </summary>
@@ -161,13 +170,13 @@ protected string GetGloballyUniqueName(string resourceName)
161170
/// <param name="parameter">The <see cref="Parameter"/> to assign.</param>
162171
private protected void AssignProperty(object instance, string propertyName, Parameter parameter)
163172
{
164-
if (ParameterOverrides.TryGetValue(instance, out var overrides))
173+
if (PropertyOverrides.TryGetValue(instance, out var overrides))
165174
{
166-
overrides[propertyName] = parameter;
175+
overrides[propertyName] = new PropertyOverride(parameter: parameter);
167176
}
168177
else
169178
{
170-
ParameterOverrides.Add(instance, new Dictionary<string, Parameter> { { propertyName, parameter } });
179+
PropertyOverrides.Add(instance, new Dictionary<string, PropertyOverride> { { propertyName, new PropertyOverride(parameter: parameter) } });
171180
}
172181
Scope.AddParameter(parameter);
173182
//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.
@@ -179,11 +188,11 @@ private protected void AssignProperty(object instance, string propertyName, stri
179188
{
180189
if (PropertyOverrides.TryGetValue(instance, out var overrides))
181190
{
182-
overrides[propertyName] = propertyValue;
191+
overrides[propertyName] = new PropertyOverride(propertyValue: propertyValue);
183192
}
184193
else
185194
{
186-
PropertyOverrides.Add(instance, new Dictionary<string, string> { { propertyName, propertyValue } });
195+
PropertyOverrides.Add(instance, new Dictionary<string, PropertyOverride> { { propertyName, new PropertyOverride(propertyValue: propertyValue) } });
187196
}
188197
}
189198

@@ -262,15 +271,6 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options)
262271
}
263272

264273
var bicepOptions = new BicepModelReaderWriterOptions();
265-
foreach (var parameter in ParameterOverrides)
266-
{
267-
var dict = new Dictionary<string, string>();
268-
foreach (var kvp in parameter.Value)
269-
{
270-
dict.Add(kvp.Key, kvp.Value.GetParameterString(ModuleScope!));
271-
}
272-
bicepOptions.ParameterOverrides.Add(parameter.Key, dict);
273-
}
274274
foreach (var propertyOverride in PropertyOverrides)
275275
{
276276
if (!bicepOptions.ParameterOverrides.TryGetValue(propertyOverride.Key, out var dict))
@@ -280,7 +280,7 @@ private BinaryData SerializeModule(ModelReaderWriterOptions options)
280280
}
281281
foreach (var kvp in propertyOverride.Value)
282282
{
283-
dict.Add(kvp.Key, kvp.Value);
283+
dict[kvp.Key] = kvp.Value.Parameter?.GetParameterString(ModuleScope!) ?? kvp.Value.PropertyValue;
284284
}
285285
}
286286
var data = ModelReaderWriter.Write(ResourceData, bicepOptions).ToMemory();

0 commit comments

Comments
 (0)