Skip to content

Commit

Permalink
Handling File Targeted Configuration and fixing Environment Computed …
Browse files Browse the repository at this point in the history
…Values (#39)

Adding Computed values to Environment, also adding file targeted config
to ALZ-BICEP-CONFIG

# Pull Request

## Issue
 
Fixes #38

## Description

Handling 'Computed' values for the Environment file. (This needs a
refactor of how we handle computed values, which I'll do after this
change #40)
Supporting file specific replacement values with configuration.
```
{
    Name = {Name of the setting in Bicep config or Environment}
    File = {FileName}
    Destination = {Parameters|Environment}
}
```

## License

By submitting this pull request, I confirm that my contribution is made
under the terms of the projects associated license.
  • Loading branch information
lovelysandwich authored Mar 31, 2023
1 parent aab11e0 commit ed70360
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 7 deletions.
39 changes: 34 additions & 5 deletions src/ALZ/Assets/alz-bicep-config/v0.14.1-pre.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@
"Description": "The identifier of the Identity Subscription. (e.g '00000000-0000-0000-0000-000000000000')",
"Valid": "^( {){0,1}[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(}){0,1}$",
"Targets": [
{
{
"Name": "IDENTITY_SUBSCRIPTION_ID",
"Destination": "Environment"
}
Expand Down Expand Up @@ -310,7 +310,7 @@
"Valid": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"Targets": [
{
"Name":"parPolicyAssignmentParameters.value.emailSecurityContact.value",
"Name": "parPolicyAssignmentParameters.value.emailSecurityContact.value",
"Destination": "Parameters"
}
],
Expand All @@ -327,7 +327,6 @@
}
]
},

"LogAnalyticsResourceId": {
"Type": "Computed",
"Value": "/subscriptions/{%ManagementSubscriptionId%}/resourcegroups/alz-logging/providers/microsoft.operationalinsights/workspaces/alz-log-analytics",
Expand Down Expand Up @@ -384,7 +383,7 @@
}
]
},
"VirtualWanName":{
"VirtualWanName": {
"Type": "Computed",
"Value": "alz-vwan-{%Location%}",
"Targets": [
Expand All @@ -394,7 +393,7 @@
}
]
},
"FirewallPoliciesName":{
"FirewallPoliciesName": {
"Type": "Computed",
"Value": "alz-azfwpolicy-{%Location%}",
"Targets": [
Expand Down Expand Up @@ -453,6 +452,36 @@
"Destination": "Environment"
}
]
},
"ConnectivityResourceGroupName": {
"Type": "Computed",
"Value": "rg-{%Prefix%}-connectivity",
"Targets": [
{
"Name": "CONNECTIVITY_RESOURCE_GROUP",
"Destination": "Environment"
},
{
"File": "resourceGroupConnectivity.parameters.all.json",
"Name": "parResourceGroupName.value",
"Destination": "Parameters"
}
]
},
"LoggingResourceGroupName": {
"Type": "Computed",
"Value": "rg-{%Prefix%}-logging",
"Targets": [
{
"Name": "LOGGING_RESOURCE_GROUP",
"Destination": "Environment"
},
{
"File": "resourceGroupLoggingAndSentinel.parameters.all.json",
"Name": "parResourceGroupName.value",
"Destination": "Parameters"
}
]
}
}
}
8 changes: 7 additions & 1 deletion src/ALZ/Private/Build-ALZDeploymentEnvFile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ function Build-ALZDeploymentEnvFile {
foreach ($configurationValue in $configuration.PsObject.Properties) {
foreach ($target in $configurationValue.Value.Targets) {
if ($target.Destination -eq "Environment") {
Add-Content -Path $envFile -Value "$($($target.Name))=`"$($configurationValue.Value.Value)`"" | Out-String | Write-Verbose

$formattedValue = $configurationValue.Value.Value
if ($configurationValue.Value.Type -eq "Computed") {
$formattedValue = Format-TokenizedConfigurationString -tokenizedString $configurationValue.Value.Value -configuration $configuration
}

Add-Content -Path $envFile -Value "$($($target.Name))=`"$formattedValue`"" | Out-String | Write-Verbose
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/ALZ/Private/Edit-ALZConfigurationFilesInPlace.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ function Edit-ALZConfigurationFilesInPlace {

foreach ($configKey in $configuration.PsObject.Properties) {
foreach ($target in $configKey.Value.Targets) {
# Is this configuration value for this file?
$targetedAtThisFile = $null -eq $target.File -or $target.File -eq $file.Name
if ($targetedAtThisFile -eq $false) {
continue
}

# Find the appropriate item which will be changed in the Bicep file.
# Remove array '[' ']' characters so we can use the index value direct.
Expand Down Expand Up @@ -56,7 +61,7 @@ function Edit-ALZConfigurationFilesInPlace {

} while (($null -ne $bicepConfigNode) -and ($index -lt $propertyNames.Length - 1))

# If we're here, we've got the object at the bottom of the hierarchy - and we can modify values on it.
# If we're here, we can modify this file and we've got an actual object specified by the Name path value - and we can modify values on it.
if ($target.Destination -eq "Parameters" -and $null -ne $bicepConfigNode) {
$leafPropertyName = $propertyNames[-1]

Expand Down
32 changes: 32 additions & 0 deletions src/Tests/Unit/Private/Build-ALZDeploymentEnvFile.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,38 @@ InModuleScope 'ALZ' {
Should -Invoke New-Item -ParameterFilter { $Path -match ".env$" } -Scope It -Times 1 -Exactly
Should -Invoke Add-Content -Scope It -Times 1 -Exactly
}

It 'Handles Computed values correctly and adds to the .env file.' {

Mock -CommandName New-Item
Mock -CommandName Add-Content

$configuration = [pscustomobject]@{
Setting1 = [pscustomobject]@{
Targets = @(
[pscustomobject]@{
Name = "Setting1"
Destination = "Environment"
})
Value = "Test"
}
Setting2 = [pscustomobject]@{
Targets = @(
[pscustomobject]@{
Name = "Setting2"
Destination = "Environment"
})
Type = "Computed"
Value = "{%Setting1%}"
}
}

Build-ALZDeploymentEnvFile -configuration $configuration -destination "test"

Should -Invoke New-Item -ParameterFilter { $Path -match ".env$" } -Scope It -Times 1 -Exactly
Should -Invoke Add-Content -ParameterFilter { $Value -match "^Setting1=`"Test`"$" } -Scope It -Times 1 -Exactly
Should -Invoke Add-Content -ParameterFilter { $Value -match "^Setting2=`"Test`"$" } -Scope It -Times 1 -Exactly
}
}
}
}
82 changes: 82 additions & 0 deletions src/Tests/Unit/Private/Edit-ALZConfigurationFilesInPlace.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,88 @@ InModuleScope 'ALZ' {
-ParameterFilter { $FilePath -eq $testFile1Name -and $InputObject -eq $expectedContent } `
-Scope It
}

It 'Multiple files with file specific configuration should be changed correctly' {
$defaultConfig = [pscustomobject]@{
Value1 = [pscustomobject]@{
Description = "The prefix that will be added to all resources created by this deployment."
Targets = @(
[pscustomobject]@{
File = "test1.parameters.json"
Name = "parCompanyPrefix.value"
Destination = "Parameters"
})
Value = "value1"
DefaultValue = "alz"
}
Value2 = [pscustomobject]@{
Description = "The prefix that will be added to all resources created by this deployment."
Targets = @(
[pscustomobject]@{
File = "test2.parameters.json"
Name = "parCompanyPrefix.value"
Destination = "Parameters"
})
Value = "value2"
DefaultValue = "alz"
}
}

$firstFileContent = '{
"parameters": {
"parCompanyPrefix": {
"value": ""
},
}
}'
$secondFileContent = '{
"parameters": {
"parCompanyPrefix": {
"value": ""
},
}
}'

Mock -CommandName Get-ChildItem -ParameterFilter { $Path -match 'config$' } -MockWith {
@(
[PSCustomObject]@{
Name = 'test1.parameters.json'
FullName = 'test1.parameters.json'
},
[PSCustomObject]@{
Name = 'test2.parameters.json'
FullName = 'test2.parameters.json'
}
)
}

Mock -CommandName Get-Content -ParameterFilter { $Path -eq 'test1.parameters.json' } -MockWith {
$firstFileContent
}
Mock -CommandName Get-Content -ParameterFilter { $Path -eq 'test2.parameters.json' } -MockWith {
$secondFileContent
}

Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination '.' -configuration $defaultConfig

Should -Invoke -CommandName Out-File -Scope It -Times 2

# Assert that the file was written back with the new values
$contentAfterParsing = ConvertFrom-Json -InputObject $firstFileContent -AsHashtable
$contentAfterParsing.parameters.parCompanyPrefix.value = 'value1'

$contentStringAfterParsing = ConvertTo-Json -InputObject $contentAfterParsing
Write-InformationColored $contentStringAfterParsing -ForegroundColor Yellow -InformationAction Continue
Should -Invoke -CommandName Out-File -ParameterFilter { $FilePath -eq "test1.parameters.json" -and $InputObject -eq $contentStringAfterParsing } -Scope It

$contentAfterParsing = ConvertFrom-Json -InputObject $secondFileContent -AsHashtable
$contentAfterParsing.parameters.parCompanyPrefix.value = 'value2'

$contentStringAfterParsing = ConvertTo-Json -InputObject $contentAfterParsing
Write-InformationColored $contentStringAfterParsing -ForegroundColor Yellow -InformationAction Continue
Should -Invoke -CommandName Out-File -ParameterFilter { $FilePath -eq "test2.parameters.json" -and $InputObject -eq $contentStringAfterParsing } -Scope It

}
}
}
}

0 comments on commit ed70360

Please sign in to comment.