Skip to content

Commit 36b05e8

Browse files
committed
Add IPv6 examples and resolve remarks
1 parent 60ef313 commit 36b05e8

File tree

9 files changed

+149
-67
lines changed

9 files changed

+149
-67
lines changed

docs/reference/schemas/config/functions/cidrHost.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,48 @@ messages: []
158158
hadErrors: false
159159
```
160160

161+
### Example 4 - IPv6 host address allocation
162+
163+
This configuration demonstrates calculating host addresses within an IPv6
164+
network, showing that the function supports both IPv4 and IPv6 address families.
165+
166+
```yaml
167+
# cidrHost.example.4.dsc.config.yaml
168+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
169+
parameters:
170+
ipv6Network:
171+
type: string
172+
defaultValue: 2001:db8::/64
173+
resources:
174+
- name: IPv6 host addresses
175+
type: Microsoft.DSC.Debug/Echo
176+
properties:
177+
output:
178+
network: "[parameters('ipv6Network')]"
179+
router: "[cidrHost(parameters('ipv6Network'), 1)]"
180+
server1: "[cidrHost(parameters('ipv6Network'), 10)]"
181+
server2: "[cidrHost(parameters('ipv6Network'), 11)]"
182+
```
183+
184+
```bash
185+
dsc config get --file cidrHost.example.4.dsc.config.yaml
186+
```
187+
188+
```yaml
189+
results:
190+
- name: IPv6 host addresses
191+
type: Microsoft.DSC.Debug/Echo
192+
result:
193+
actualState:
194+
output:
195+
network: 2001:db8::/64
196+
router: 2001:db8::1
197+
server1: 2001:db8::a
198+
server2: 2001:db8::b
199+
messages: []
200+
hadErrors: false
201+
```
202+
161203
## Parameters
162204

163205
### cidrNotation

docs/reference/schemas/config/functions/cidrSubnet.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,51 @@ messages: []
173173
hadErrors: false
174174
```
175175

176+
### Example 4 - IPv6 subnet allocation
177+
178+
This configuration demonstrates creating IPv6 subnets from a larger IPv6 address
179+
block, showing support for both IPv4 and IPv6 address families.
180+
181+
```yaml
182+
# cidrSubnet.example.4.dsc.config.yaml
183+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
184+
parameters:
185+
ipv6BaseNetwork:
186+
type: string
187+
defaultValue: 2001:db8::/32
188+
subnetPrefix:
189+
type: int
190+
defaultValue: 48
191+
resources:
192+
- name: IPv6 subnets
193+
type: Microsoft.DSC.Debug/Echo
194+
properties:
195+
output:
196+
baseNetwork: "[parameters('ipv6BaseNetwork')]"
197+
subnet0: "[cidrSubnet(parameters('ipv6BaseNetwork'), parameters('subnetPrefix'), 0)]"
198+
subnet1: "[cidrSubnet(parameters('ipv6BaseNetwork'), parameters('subnetPrefix'), 1)]"
199+
subnet10: "[cidrSubnet(parameters('ipv6BaseNetwork'), parameters('subnetPrefix'), 10)]"
200+
```
201+
202+
```bash
203+
dsc config get --file cidrSubnet.example.4.dsc.config.yaml
204+
```
205+
206+
```yaml
207+
results:
208+
- name: IPv6 subnets
209+
type: Microsoft.DSC.Debug/Echo
210+
result:
211+
actualState:
212+
output:
213+
baseNetwork: 2001:db8::/32
214+
subnet0: 2001:db8::/48
215+
subnet1: 2001:db8:1::/48
216+
subnet10: 2001:db8:a::/48
217+
messages: []
218+
hadErrors: false
219+
```
220+
176221
## Parameters
177222

178223
### cidrNotation

docs/reference/schemas/config/functions/parseCidr.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,41 @@ messages: []
157157
hadErrors: false
158158
```
159159

160+
### Example 4 - Parse IPv6 CIDR notation
161+
162+
This configuration demonstrates parsing IPv6 CIDR notation, showing that the
163+
function supports both IPv4 and IPv6 address families.
164+
165+
```yaml
166+
# parseCidr.example.4.dsc.config.yaml
167+
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
168+
resources:
169+
- name: Parse IPv6 network
170+
type: Microsoft.DSC.Debug/Echo
171+
properties:
172+
output: "[parseCidr('2001:db8::/32')]"
173+
```
174+
175+
```bash
176+
dsc config get --file parseCidr.example.4.dsc.config.yaml
177+
```
178+
179+
```yaml
180+
results:
181+
- name: Parse IPv6 network
182+
type: Microsoft.DSC.Debug/Echo
183+
result:
184+
actualState:
185+
output:
186+
network: 2001:db8::
187+
netmask: ffff:ffff::
188+
firstUsable: 2001:db8::
189+
lastUsable: 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff
190+
cidr: 32
191+
messages: []
192+
hadErrors: false
193+
```
194+
160195
## Parameters
161196

162197
### cidrNotation
@@ -195,9 +230,8 @@ For **IPv6** addresses:
195230

196231
- `network`: The network address (string)
197232
- `netmask`: The network mask (string)
198-
- `broadcast`: The broadcast address (string)
199233
- `firstUsable`: The first usable address (same as network for IPv6) (string)
200-
- `lastUsable`: The last usable address (same as broadcast for IPv6) (string)
234+
- `lastUsable`: The last address in the network (string)
201235
- `cidr`: The prefix length (integer)
202236

203237
**Note**: For `/32` IPv4 networks (single host), `firstUsable` and `lastUsable`

dsc/tests/dsc_functions.tests.ps1

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ Describe 'tests for function expressions' {
13651365
}
13661366

13671367
It 'parseCidr fails with invalid CIDR: <cidr>' -TestCases @(
1368-
@{ cidr = 'invalid'; errorMatch = 'Invalid CIDR notation' }
1368+
@{ cidr = '192.168.1/24'; errorMatch = 'Invalid CIDR notation' }
13691369
@{ cidr = '192.168.1.0/33'; errorMatch = 'Invalid CIDR notation' }
13701370
@{ cidr = '192.168.1.256/24'; errorMatch = 'Invalid CIDR notation' }
13711371
) {
@@ -1444,7 +1444,7 @@ Describe 'tests for function expressions' {
14441444
@{ testName = 'new CIDR too small'; network = '10.144.0.0/20'; newCidr = 16; index = 0; errorMatch = 'equal to or larger' }
14451445
@{ testName = 'invalid IPv4 prefix'; network = '10.144.0.0/20'; newCidr = 33; index = 0; errorMatch = 'Invalid IPv4 prefix' }
14461446
@{ testName = 'invalid IPv6 prefix'; network = '2001:db8::/32'; newCidr = 129; index = 0; errorMatch = 'Invalid IPv6 prefix' }
1447-
@{ testName = 'invalid CIDR format'; network = 'invalid'; newCidr = 24; index = 0; errorMatch = 'Invalid CIDR notation' }
1447+
@{ testName = 'invalid CIDR format'; network = '10.0.0/16'; newCidr = 24; index = 0; errorMatch = 'Invalid CIDR notation' }
14481448
) {
14491449
param($testName, $network, $newCidr, $index, $errorMatch)
14501450

@@ -1501,30 +1501,23 @@ Describe 'tests for function expressions' {
15011501
$out.results[0].result.actualState.output | Should -BeExactly $expected
15021502
}
15031503

1504-
It 'cidrHost handles /31 point-to-point' {
1505-
$config_yaml = @"
1506-
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
1507-
resources:
1508-
- name: Echo
1509-
type: Microsoft.DSC.Debug/Echo
1510-
properties:
1511-
output: "[cidrHost('192.168.1.0/31', 0)]"
1512-
"@
1513-
$out = $config_yaml | dsc config get -f - | ConvertFrom-Json
1514-
$LASTEXITCODE | Should -Be 0
1515-
$out.results[0].result.actualState.output | Should -BeExactly '192.168.1.0'
1504+
It 'cidrHost handles /31 point-to-point: index <index>' -TestCases @(
1505+
@{ network = '192.168.1.0/31'; index = 0; expected = '192.168.1.0' }
1506+
@{ network = '192.168.1.0/31'; index = 1; expected = '192.168.1.1' }
1507+
) {
1508+
param($network, $index, $expected)
15161509

15171510
$config_yaml = @"
15181511
`$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
15191512
resources:
15201513
- name: Echo
15211514
type: Microsoft.DSC.Debug/Echo
15221515
properties:
1523-
output: "[cidrHost('192.168.1.0/31', 1)]"
1516+
output: "[cidrHost('$network', $index)]"
15241517
"@
15251518
$out = $config_yaml | dsc config get -f - | ConvertFrom-Json
15261519
$LASTEXITCODE | Should -Be 0
1527-
$out.results[0].result.actualState.output | Should -BeExactly '192.168.1.1'
1520+
$out.results[0].result.actualState.output | Should -BeExactly $expected
15281521
}
15291522

15301523
It 'cidrHost works with IPv6' {
@@ -1546,7 +1539,7 @@ Describe 'tests for function expressions' {
15461539
@{ testName = '/128 has no usable hosts'; network = '2001:db8::1/128'; index = 0; errorMatch = 'no usable host' }
15471540
@{ testName = 'index out of range'; network = '192.168.1.0/24'; index = 254; errorMatch = 'out of range' }
15481541
@{ testName = 'negative index'; network = '192.168.1.0/24'; index = -1; errorMatch = 'negative' }
1549-
@{ testName = 'invalid CIDR'; network = 'invalid'; index = 0; errorMatch = 'Invalid CIDR notation' }
1542+
@{ testName = 'invalid CIDR'; network = '192.168.1.0.0/24'; index = 0; errorMatch = 'Invalid CIDR notation' }
15501543
) {
15511544
param($testName, $network, $index, $errorMatch)
15521545

lib/dsc-lib/locales/en-us.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,8 +471,6 @@ invalidCidr = "Invalid CIDR notation: '%{cidr}'. Expected format: IP/prefix (e.g
471471
[functions.cidrHost]
472472
description = "Calculates the usable IP address of the host with the specified index on the specified IP address range in CIDR notation"
473473
invoked = "cidrHost function"
474-
invalidNetwork = "Network parameter must be a string"
475-
invalidHostIndex = "HostIndex parameter must be an integer"
476474
negativeHostIndex = "HostIndex cannot be negative"
477475
invalidCidr = "Invalid CIDR notation: '%{cidr}'. Expected format: IP/prefix (e.g., '192.168.1.0/24' or '2001:db8::/32')"
478476
noUsableHosts = "Network has no usable host addresses (single IP address)"
@@ -482,9 +480,6 @@ hostCalculationFailed = "Failed to calculate host address"
482480
[functions.cidrSubnet]
483481
description = "Splits the specified IP address range in CIDR notation into subnets with a new CIDR value and returns the IP address range of the subnet with the specified index"
484482
invoked = "cidrSubnet function"
485-
invalidNetwork = "Network parameter must be a string"
486-
invalidNewCidr = "NewCIDR parameter must be an integer"
487-
invalidSubnetIndex = "SubnetIndex parameter must be an integer"
488483
negativeSubnetIndex = "SubnetIndex cannot be negative"
489484
invalidCidr = "Invalid CIDR notation: '%{cidr}'. Expected format: IP/prefix (e.g., '192.168.1.0/24' or '2001:db8::/32')"
490485
invalidPrefixV4 = "Invalid IPv4 prefix: %{prefix}. Must be between 0 and 32"

lib/dsc-lib/src/functions/cidr_host.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Function for CidrHost {
1818
FunctionMetadata {
1919
name: "cidrHost".to_string(),
2020
description: t!("functions.cidrHost.description").to_string(),
21-
category: vec![FunctionCategory::String],
21+
category: vec![FunctionCategory::Cidr],
2222
min_args: 2,
2323
max_args: 2,
2424
accepted_arg_ordered_types: vec![
@@ -33,19 +33,8 @@ impl Function for CidrHost {
3333
fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> {
3434
debug!("{}", t!("functions.cidrHost.invoked"));
3535

36-
let cidr_string = args[0].as_str().ok_or_else(|| {
37-
DscError::FunctionArg(
38-
"cidrHost".to_string(),
39-
t!("functions.cidrHost.invalidNetwork").to_string(),
40-
)
41-
})?;
42-
43-
let host_index = args[1].as_i64().ok_or_else(|| {
44-
DscError::FunctionArg(
45-
"cidrHost".to_string(),
46-
t!("functions.cidrHost.invalidHostIndex").to_string(),
47-
)
48-
})?;
36+
let cidr_string = args[0].as_str().unwrap();
37+
let host_index = args[1].as_i64().unwrap();
4938

5039
if host_index < 0 {
5140
return Err(DscError::FunctionArg(
@@ -62,15 +51,15 @@ impl Function for CidrHost {
6251
})?;
6352

6453
let result = match network {
65-
IpNetwork::V4(net) => calculate_ipv4_host(net, host_index as u32)?,
66-
IpNetwork::V6(net) => calculate_ipv6_host(net, host_index as u128)?,
54+
IpNetwork::V4(net) => calculate_ipv4_host(&net, host_index as u32)?,
55+
IpNetwork::V6(net) => calculate_ipv6_host(&net, host_index as u128)?,
6756
};
6857

6958
Ok(Value::String(result))
7059
}
7160
}
7261

73-
fn calculate_ipv4_host(net: Ipv4Network, host_index: u32) -> Result<String, DscError> {
62+
fn calculate_ipv4_host(net: &Ipv4Network, host_index: u32) -> Result<String, DscError> {
7463
let prefix = net.prefix();
7564

7665
// Special case: /32 has no usable hosts
@@ -125,7 +114,7 @@ fn calculate_ipv4_host(net: Ipv4Network, host_index: u32) -> Result<String, DscE
125114
Ok(host_ip.to_string())
126115
}
127116

128-
fn calculate_ipv6_host(net: Ipv6Network, host_index: u128) -> Result<String, DscError> {
117+
fn calculate_ipv6_host(net: &Ipv6Network, host_index: u128) -> Result<String, DscError> {
129118
let prefix = net.prefix();
130119

131120
if prefix == 128 {

lib/dsc-lib/src/functions/cidr_subnet.rs

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl Function for CidrSubnet {
1919
FunctionMetadata {
2020
name: "cidrSubnet".to_string(),
2121
description: t!("functions.cidrSubnet.description").to_string(),
22-
category: vec![FunctionCategory::String],
22+
category: vec![FunctionCategory::Cidr],
2323
min_args: 3,
2424
max_args: 3,
2525
accepted_arg_ordered_types: vec![
@@ -35,26 +35,9 @@ impl Function for CidrSubnet {
3535
fn invoke(&self, args: &[Value], _context: &Context) -> Result<Value, DscError> {
3636
debug!("{}", t!("functions.cidrSubnet.invoked"));
3737

38-
let cidr_string = args[0].as_str().ok_or_else(|| {
39-
DscError::FunctionArg(
40-
"cidrSubnet".to_string(),
41-
t!("functions.cidrSubnet.invalidNetwork").to_string(),
42-
)
43-
})?;
44-
45-
let new_cidr = args[1].as_i64().ok_or_else(|| {
46-
DscError::FunctionArg(
47-
"cidrSubnet".to_string(),
48-
t!("functions.cidrSubnet.invalidNewCidr").to_string(),
49-
)
50-
})? as u8;
51-
52-
let subnet_index = args[2].as_i64().ok_or_else(|| {
53-
DscError::FunctionArg(
54-
"cidrSubnet".to_string(),
55-
t!("functions.cidrSubnet.invalidSubnetIndex").to_string(),
56-
)
57-
})?;
38+
let cidr_string = args[0].as_str().unwrap();
39+
let new_cidr = args[1].as_i64().unwrap() as u8;
40+
let subnet_index = args[2].as_i64().unwrap();
5841

5942
if subnet_index < 0 {
6043
return Err(DscError::FunctionArg(

lib/dsc-lib/src/functions/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ pub struct FunctionDefinition {
346346
#[serde(deny_unknown_fields)]
347347
pub enum FunctionCategory {
348348
Array,
349+
Cidr,
349350
Comparison,
350351
Date,
351352
Deployment,
@@ -362,6 +363,7 @@ impl Display for FunctionCategory {
362363
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363364
match self {
364365
FunctionCategory::Array => write!(f, "Array"),
366+
FunctionCategory::Cidr => write!(f, "Cidr"),
365367
FunctionCategory::Comparison => write!(f, "Comparison"),
366368
FunctionCategory::Date => write!(f, "Date"),
367369
FunctionCategory::Deployment => write!(f, "Deployment"),

lib/dsc-lib/src/functions/parse_cidr.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl Function for ParseCidr {
1818
FunctionMetadata {
1919
name: "parseCidr".to_string(),
2020
description: t!("functions.parseCidr.description").to_string(),
21-
category: vec![FunctionCategory::Object],
21+
category: vec![FunctionCategory::Cidr],
2222
min_args: 1,
2323
max_args: 1,
2424
accepted_arg_ordered_types: vec![vec![FunctionArgKind::String]],
@@ -80,7 +80,6 @@ impl Function for ParseCidr {
8080
json!({
8181
"network": network_addr.to_string(),
8282
"netmask": net.mask().to_string(),
83-
"broadcast": broadcast_addr.to_string(),
8483
"firstUsable": network_addr.to_string(),
8584
"lastUsable": broadcast_addr.to_string(),
8685
"cidr": net.prefix()
@@ -216,7 +215,7 @@ mod tests {
216215
assert_eq!(obj.get("network").unwrap().as_str().unwrap(), "2001:db8::");
217216
assert_eq!(obj.get("cidr").unwrap().as_u64().unwrap(), 32);
218217
assert!(obj.get("netmask").is_some());
219-
assert!(obj.get("broadcast").is_some());
218+
assert!(obj.get("broadcast").is_none());
220219
assert!(obj.get("firstUsable").is_some());
221220
assert!(obj.get("lastUsable").is_some());
222221
}
@@ -232,7 +231,7 @@ mod tests {
232231
assert_eq!(obj.get("network").unwrap().as_str().unwrap(), "fe80::");
233232
assert_eq!(obj.get("cidr").unwrap().as_u64().unwrap(), 64);
234233
assert!(obj.get("netmask").is_some());
235-
assert!(obj.get("broadcast").is_some());
234+
assert!(obj.get("broadcast").is_none());
236235
}
237236

238237
#[test]

0 commit comments

Comments
 (0)