Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions api/v1alpha1/ironic_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ type Inspection struct {
VLANInterfaces []string `json:"vlanInterfaces,omitempty"`
}

// DHCPRange defines a DHCP range for a subnet served via DHCP relay agents.
type DHCPRange struct {
// NetworkCIDR is the CIDR of the subnet. Required.
NetworkCIDR string `json:"networkCIDR"`

// RangeBegin is the first IP that can be given to hosts. Must be inside NetworkCIDR.
RangeBegin string `json:"rangeBegin"`

// RangeEnd is the last IP that can be given to hosts. Must be inside NetworkCIDR.
RangeEnd string `json:"rangeEnd"`
}

type DHCP struct {
// DNSAddress is the IP address of the DNS server to pass to hosts via DHCP.
// Must not be set together with ServeDNS.
Expand Down Expand Up @@ -84,6 +96,11 @@ type DHCP struct {
// RangeEnd is the last IP that can be given to hosts. Must be inside NetworkCIDR.
RangeEnd string `json:"rangeEnd,omitempty"`

// NetworkRanges is a list of additional DHCP ranges for subnets served via DHCP relay agents.
// Each range defines a separate subnet. The provisioning IP does not need to be within these subnets.
// +optional
NetworkRanges []DHCPRange `json:"networkRanges,omitempty"`

// ServeDNS is set to true to pass the provisioning host as the DNS server on the provisioning network.
// Must not be set together with DNSAddress.
// +optional
Expand Down
20 changes: 20 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions config/crd/bases/ironic.metal3.io_ironics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,32 @@ spec:
description: NetworkCIDR is a CIDR of the provisioning network.
Required.
type: string
networkRanges:
description: |-
NetworkRanges is a list of additional DHCP ranges for subnets served via DHCP relay agents.
Each range defines a separate subnet. The provisioning IP does not need to be within these subnets.
items:
description: DHCPRange defines a DHCP range for a subnet
served via DHCP relay agents.
properties:
networkCIDR:
description: NetworkCIDR is the CIDR of the subnet.
Required.
type: string
rangeBegin:
description: RangeBegin is the first IP that can be
given to hosts. Must be inside NetworkCIDR.
type: string
rangeEnd:
description: RangeEnd is the last IP that can be given
to hosts. Must be inside NetworkCIDR.
type: string
required:
- networkCIDR
- rangeBegin
- rangeEnd
type: object
type: array
rangeBegin:
description: RangeBegin is the first IP that can be given
to hosts. Must be inside NetworkCIDR.
Expand Down
49 changes: 49 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,14 @@ There is no API-side validation. Most users will leave this unset.<br/>
NetworkCIDR is a CIDR of the provisioning network. Required.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b><a href="#ironicspecnetworkingdhcpnetworkrangesindex">networkRanges</a></b></td>
<td>[]object</td>
<td>
NetworkRanges is a list of additional DHCP ranges for subnets served via DHCP relay agents.
Each range defines a separate subnet. The provisioning IP does not need to be within these subnets.<br/>
</td>
<td>false</td>
</tr><tr>
<td><b>rangeBegin</b></td>
<td>string</td>
Expand All @@ -641,6 +649,47 @@ Must not be set together with DNSAddress.<br/>
</table>


### Ironic.spec.networking.dhcp.networkRanges[index]
<sup><sup>[↩ Parent](#ironicspecnetworkingdhcp)</sup></sup>



DHCPRange defines a DHCP range for a subnet served via DHCP relay agents.

<table>
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
</tr>
</thead>
<tbody><tr>
<td><b>networkCIDR</b></td>
<td>string</td>
<td>
NetworkCIDR is the CIDR of the subnet. Required.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>rangeBegin</b></td>
<td>string</td>
<td>
RangeBegin is the first IP that can be given to hosts. Must be inside NetworkCIDR.<br/>
</td>
<td>true</td>
</tr><tr>
<td><b>rangeEnd</b></td>
<td>string</td>
<td>
RangeEnd is the last IP that can be given to hosts. Must be inside NetworkCIDR.<br/>
</td>
<td>true</td>
</tr></tbody>
</table>


### Ironic.spec.overrides
<sup><sup>[↩ Parent](#ironicspec)</sup></sup>

Expand Down
22 changes: 18 additions & 4 deletions pkg/ironic/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,12 +506,26 @@
}

func buildDHCPRange(dhcp *metal3api.DHCP) string {
prefix, err := netip.ParsePrefix(dhcp.NetworkCIDR)
if err != nil {
return "" // don't disable your webhooks people
var parts []string

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)

Check failure on line 509 in pkg/ironic/containers.go

View workflow job for this annotation

GitHub Actions / lint

Consider pre-allocating `parts` (prealloc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please address the linter issue


// Primary range (from flat fields)
if dhcp.NetworkCIDR != "" && dhcp.RangeBegin != "" && dhcp.RangeEnd != "" {
prefix, err := netip.ParsePrefix(dhcp.NetworkCIDR)
if err == nil {
parts = append(parts, fmt.Sprintf("%s,%s,%d", dhcp.RangeBegin, dhcp.RangeEnd, prefix.Bits()))
}
}

// Additional network ranges
for _, r := range dhcp.NetworkRanges {
prefix, err := netip.ParsePrefix(r.NetworkCIDR)
if err != nil {
continue
}
parts = append(parts, fmt.Sprintf("%s,%s,%d", r.RangeBegin, r.RangeEnd, prefix.Bits()))
}

return fmt.Sprintf("%s,%s,%d", dhcp.RangeBegin, dhcp.RangeEnd, prefix.Bits())
return strings.Join(parts, ";")
}

func buildDNSIP(dhcp *metal3api.DHCP) string {
Expand Down
82 changes: 82 additions & 0 deletions pkg/ironic/containers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,88 @@ func TestIronicPortEnvVars(t *testing.T) {
}
}

func TestBuildDHCPRange(t *testing.T) {
testCases := []struct {
name string
dhcp *metal3api.DHCP
expected string
}{
{
name: "primary range only",
dhcp: &metal3api.DHCP{
NetworkCIDR: "192.168.1.0/24",
RangeBegin: "192.168.1.10",
RangeEnd: "192.168.1.200",
},
expected: "192.168.1.10,192.168.1.200,24",
},
{
name: "networkRanges only",
dhcp: &metal3api.DHCP{
NetworkRanges: []metal3api.DHCPRange{
{
NetworkCIDR: "192.168.1.0/24",
RangeBegin: "192.168.1.10",
RangeEnd: "192.168.1.200",
},
{
NetworkCIDR: "192.168.2.0/24",
RangeBegin: "192.168.2.10",
RangeEnd: "192.168.2.200",
},
},
},
expected: "192.168.1.10,192.168.1.200,24;192.168.2.10,192.168.2.200,24",
},
{
name: "primary range and networkRanges combined",
dhcp: &metal3api.DHCP{
NetworkCIDR: "10.0.0.0/16",
RangeBegin: "10.0.1.1",
RangeEnd: "10.0.1.254",
NetworkRanges: []metal3api.DHCPRange{
{
NetworkCIDR: "192.168.1.0/24",
RangeBegin: "192.168.1.10",
RangeEnd: "192.168.1.200",
},
},
},
expected: "10.0.1.1,10.0.1.254,16;192.168.1.10,192.168.1.200,24",
},
{
name: "IPv6 networkRanges",
dhcp: &metal3api.DHCP{
NetworkRanges: []metal3api.DHCPRange{
{
NetworkCIDR: "fd69:158d:692a:1::/64",
RangeBegin: "fd69:158d:692a:1::3000",
RangeEnd: "fd69:158d:692a:1::3fff",
},
{
NetworkCIDR: "fd69:158d:692a:2::/64",
RangeBegin: "fd69:158d:692a:2::3000",
RangeEnd: "fd69:158d:692a:2::3fff",
},
},
},
expected: "fd69:158d:692a:1::3000,fd69:158d:692a:1::3fff,64;fd69:158d:692a:2::3000,fd69:158d:692a:2::3fff,64",
},
{
name: "empty DHCP",
dhcp: &metal3api.DHCP{},
expected: "",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := buildDHCPRange(tc.dhcp)
assert.Equal(t, tc.expected, result)
})
}
}

func TestPrometheusExporterEnvVars(t *testing.T) {
testCases := []struct {
name string
Expand Down
Loading
Loading