feat(AzLocal.DeploymentAutomation): v1.0.1 - optional dnsServers in -NetworkSettingsJson#15
Conversation
…NetworkSettingsJson Adds optional 'dnsServers' array to the JSON payload accepted by -NetworkSettingsJson. When present, overrides defaults.dnsServers from naming-standards-config.json for that single deployment. - Get-AzLocalNetworkSettingsFromJson: parse + validate optional dnsServers; absent/null/empty array means 'no override' - Start-AzLocalTemplateDeployment: three-tier precedence (-DnsServers > JSON.dnsServers > config default) - Start-AzLocalCsvDeployment: unchanged - CSV DnsServers column still maps to -DnsServers parameter (highest precedence) - Tests: +6 unit tests for dnsServers parser + 1 source-text precedence assertion; bumped version assertions to 1.0.1; fixed stale Disaggregated TypeOfDeployment list - README.md: documented new optional field + 'DNS Servers Precedence (v1.0.1)' subsection - Manifest: ModuleVersion=1.0.1; detailed release notes (8657 chars, under 10000 PSGallery cap) - psm1: version banner updated to 1.0.1 Pester: 532/532 passing.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Bumps AzLocal.DeploymentAutomation to v1.0.1 and adds a per-deployment DNS override via an optional dnsServers array inside -NetworkSettingsJson, with a defined precedence order.
Changes:
- Add parsing/validation for optional
dnsServersinGet-AzLocalNetworkSettingsFromJson. - Implement three-tier DNS precedence in
Start-AzLocalTemplateDeployment(-DnsServers> JSONdnsServers> config default). - Update module versioning/docs and extend Pester coverage for the new behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| AzLocal.DeploymentAutomation/Private/Get-AzLocalNetworkSettingsFromJson.ps1 | Parses + validates optional dnsServers and returns it to callers. |
| AzLocal.DeploymentAutomation/Public/Start-AzLocalTemplateDeployment.ps1 | Applies the three-tier DNS precedence when resolving $DnsServers. |
| AzLocal.DeploymentAutomation/Tests/AzLocal.DeploymentAutomation.Tests.ps1 | Bumps version assertions and adds unit tests + a precedence guard. |
| AzLocal.DeploymentAutomation/README.md | Documents dnsServers in JSON and the DNS precedence rules. |
| AzLocal.DeploymentAutomation/AzLocal.DeploymentAutomation.psd1 | Version bump + v1.0.1 release notes. |
| AzLocal.DeploymentAutomation/AzLocal.DeploymentAutomation.psm1 | Updates the version banner/date. |
| It 'Module should implement DnsServers precedence: -DnsServers > NetworkSettingsJson.dnsServers > config default (v1.0.1)' { | ||
| # Three-tier precedence introduced in v1.0.1. Guard against regression. | ||
| $script:ModuleContent | Should -Match 'NetworkSettings\.PSObject\.Properties\[''dnsServers''\]' | ||
| $script:ModuleContent | Should -Match 'NamingConfig\.defaults\.dnsServers' | ||
| } |
There was a problem hiding this comment.
Addressed in cb1dc45.
Loosened the regex to match the intent (NetworkSettings ... dnsServers + defaults ... dnsServers) rather than exact identifiers, so it survives variable renames and whitespace. Behaviour-level coverage already lives in the dedicated Get-AzLocalNetworkSettingsFromJson Pester block; this guard's only job is to catch a regression where someone deletes the resolution block entirely.
Chose not to extract a Resolve-AzLocalDnsServers helper - it's 8 lines of straight-line code in one call site and adding an abstraction purely to make a test pretty is the kind of over-engineering the repo's implementationDiscipline guidance flags against.
There was a problem hiding this comment.
Addressed in cb1dc45.
Loosened the regex to match the intent (NetworkSettings ... dnsServers + defaults ... dnsServers) rather than exact identifiers, so it survives variable renames and whitespace. Behaviour-level coverage already lives in the dedicated Get-AzLocalNetworkSettingsFromJson Pester block; this guard's only job is to catch a regression where someone deletes the resolution block entirely.
Chose not to extract a Resolve-AzLocalDnsServers helper - it's 8 lines of straight-line code in one call site and adding an abstraction purely to make a test pretty is the kind of over-engineering the repo's implementationDiscipline guidance flags against.
| try { | ||
| [System.Net.IPAddress]::Parse([string]$dnsIP) | Out-Null | ||
| } catch { | ||
| Write-AzLocalLog "Invalid DNS server IP address '$dnsIP' in network settings JSON." -Level Error | ||
| throw "Invalid dnsServers entry '$dnsIP'. $($_.Exception.Message)" | ||
| } |
There was a problem hiding this comment.
Addressed in cb1dc45.
Switched all four [IPAddress]::Parse sites in this file (subnetMask/defaultGateway/startingIPAddress/endingIPAddress, the nodeIPAddresses loop, and the new dnsServers block) to [IPAddress]::TryParse([ref]). This avoids the exception-handling cost and yields a consistent, actionable error message that no longer depends on localised .NET exception text. Applied uniformly across the function rather than only the new block, so the validation style stays consistent.
Error messages now look like:
Invalid IP address '10.0.0.999' for field 'defaultGateway' in network settings JSON. Provide a valid IPv4 or IPv6 address.
Invalid dnsServers entry 'not-an-ip'. Provide a valid IPv4 or IPv6 address.
Pester: 532/532 passing.
1. TryParse for IP validation (PR comment #2): - Convert all 4 [IPAddress]::Parse sites in Get-AzLocalNetworkSettingsFromJson to [IPAddress]::TryParse([ref]) - avoids exception-handling overhead and yields a stable, actionable error message (no longer depends on localised .NET exception text). Applied consistently across subnetMask, defaultGateway, startingIPAddress, endingIPAddress, nodeIPAddresses, and the new dnsServers block. 2. Soften source-text precedence guard (PR comment #1): - Replace exact-identifier regex with loose intent-based patterns so the test survives variable renames or whitespace changes. The behaviour-level coverage already lives in the dedicated parser Describe block; this guard remains as a cheap regression catch for someone deleting the resolution block entirely. - Did NOT extract a Resolve-AzLocalDnsServers helper as suggested - 8 lines of straight-line code in one call site doesn't warrant a new abstraction (per repo implementationDiscipline guidance). Pester: 532/532 passing.
Summary
Bumps AzLocal.DeploymentAutomation to v1.0.1. Adds an optional
dnsServersarray to the JSON payload accepted by the-NetworkSettingsJsonparameter onStart-AzLocalTemplateDeployment. When present, it overrides the environment-widedefaults.dnsServersfromnaming-standards-config.jsonfor that single deployment, without requiring a config file change. This makes it easier to support multiple sites with different DNS servers from one shared config file (e.g. CI/CD pipelines driving deployments to multiple regions).Precedence (highest → lowest)
-DnsServersparameter onStart-AzLocalTemplateDeployment(explicit CLI override)dnsServersarray inside-NetworkSettingsJson(per-deployment override) — new in v1.0.1defaults.dnsServersinnaming-standards-config.json(environment-wide default)Start-AzLocalCsvDeploymentis unchanged — theDnsServerscolumn incluster-deployments.csvcontinues to map to the top-level-DnsServersparameter and therefore still wins over anything embedded in the JSON, so existing CSV-driven pipelines are unaffected.Schema
{ "subnetMask": "255.255.255.0", "defaultGateway": "10.0.0.1", "startingIPAddress": "10.0.0.10", "endingIPAddress": "10.0.0.50", "nodeIPAddresses": ["10.0.0.100", "10.0.0.101"], "dnsServers": ["10.0.0.5", "10.0.0.6"], // OPTIONAL - overrides config default "sanSettings": { /* unchanged */ } }Changes
Private/Get-AzLocalNetworkSettingsFromJson.ps1dnsServers; each entry validated via[System.Net.IPAddress]::Parse; absent /$null/[]all mean "no override"Public/Start-AzLocalTemplateDeployment.ps1AzLocal.DeploymentAutomation.psd1ModuleVersion = '1.0.1'; detailed v1.0.1 release notes (8,657 chars, under PSGallery 10,000 cap)AzLocal.DeploymentAutomation.psm11.0.1,Updated: May 12th 2026README.mddnsServersdocumented as optional field; new "DNS Servers Precedence (v1.0.1)" subsectionTests/AzLocal.DeploymentAutomation.Tests.ps1DisaggregatedBackwards-compatibility
-NetworkSettingsJsonpayloads continue to work unchanged —dnsServersis strictly optional.Get-AzLocalDeploymentNetworkSettings) does not collect DNS servers; interactive deployments still inherit the config default. Set-DnsServerson the cmdlet to override interactively.Get-AzLocalNetworkSettingsFromJsongained a newdnsServersproperty (value$nullwhen not provided); existing consumers that only read the previously-documented fields are unaffected.Tests
New test cases under
Describe 'Function: Get-AzLocalNetworkSettingsFromJson'→Context 'Optional dnsServers override (v1.0.1)':$nullwhendnsServersomitted (back-compat)$nullwhendnsServersis[]Plus a source-text guard under
Describe 'Module Content'asserting the three-tier precedence block exists in the module source (prevents regression).Notes
'CSV should have valid TypeOfDeployment values'had a stale$validTypeslist missingDisaggregated(added back in v1.0.0). Without this fix, the suite was failing 1/532 onmainalready.