Skip to content
Merged
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
18 changes: 12 additions & 6 deletions pkg/tink/tink.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func GenerateHWRequest(i *seederv1alpha1.Inventory, c *seederv1alpha1.Cluster, s
// if not using StreamImage mode then define a custom ipxe url with info needed to provision harvester
if !c.Spec.StreamImageMode {
customIPXEScript, err := generateIPXEScript(c.Spec.HarvesterVersion, c.Spec.ImageURL, fmt.Sprintf("http://%s:%s/2009-04-04/user-data",
tinkStackService.Status.LoadBalancer.Ingress[0].IP, HegelDefaultPort), i.Spec.ManagementInterfaceMacAddress, i.Spec.Arch, c.Spec.VlanID)
tinkStackService.Status.LoadBalancer.Ingress[0].IP, HegelDefaultPort), i.Spec.ManagementInterfaceMacAddress, i.Spec.Arch, c.Spec.VlanID, i.Status.Address, i.Status.Netmask, i.Status.Gateway)
if err != nil {
return nil, fmt.Errorf("error generating custom ipxe script for inventory %s: %v", i.Name, err)
}
Expand Down Expand Up @@ -180,9 +180,9 @@ func generateCloudConfig(configURL, hwAddress, mode, vip, token, password, ip, s
hc.DNSNameservers = append(hc.DNSNameservers, Nameservers...)
hc.SSHAuthorizedKeys = append(hc.SSHAuthorizedKeys, SSHKeys...)
hc.Hostname = hostname
if vlanID > 1 {
hc.AfterInstallChrootCommands = []string{fmt.Sprintf("grub2-editenv /oem/grubenv set extra_cmdline=\"ifname=netboot:%s\"", hwAddress)}
}

hc.AfterInstallChrootCommands = []string{fmt.Sprintf("grub2-editenv /oem/grubenv set extra_cmdline=\"ifname=netboot:%s\"", hwAddress)}
Comment thread
ibrokethecloud marked this conversation as resolved.

hc.ManagementInterface.BondOptions = bondOptions
hc.WipeAllDisks = hc.WipeAllDisks || wipeDisks
// append installation disk to WipeDisksList if wipeDisks is called at cluster level or via config url
Expand Down Expand Up @@ -214,7 +214,7 @@ func generateCloudConfig(configURL, hwAddress, mode, vip, token, password, ip, s

// generateIPXEScript will generate an inline ipxe script similar to https://github.com/harvester/ipxe-examples/blob/main/general/ipxe-create
// and uses the same for create / join of node
func generateIPXEScript(harvesterVersion, isoURL, hegelEndpoint, macAddress, arch string, vlanID int) (string, error) {
func generateIPXEScript(harvesterVersion, isoURL, hegelEndpoint, macAddress, arch string, vlanID int, ip string, netmask string, gateway string) (string, error) {

Comment on lines 216 to 218

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

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

The generateIPXEScript signature has grown to include multiple network parameters, making call sites harder to read and easier to misuse (argument order bugs). Consider passing a small struct (e.g. a network config object) or reusing an existing network type to group ip/netmask/gateway together.

Copilot uses AI. Check for mistakes.
ipxeTemplateStruct := struct {
Version string
Expand All @@ -223,13 +223,19 @@ func generateIPXEScript(harvesterVersion, isoURL, hegelEndpoint, macAddress, arc
MacAddress string
Arch string
VlanID int
IP string
Netmask string
Gateway string
}{
Version: harvesterVersion,
ISOURL: isoURL,
HegelEndpoint: hegelEndpoint,
MacAddress: macAddress,
Arch: arch,
VlanID: vlanID,
IP: ip,
Netmask: netmask,
Gateway: gateway,
}

var output bytes.Buffer
Expand All @@ -240,7 +246,7 @@ set base {{ .ISOURL}}/{{ .Version }}
set arch {{ .Arch }}
dhcp
iflinkwait -t 5000
kernel ${base}/harvester-${version}-vmlinuz-${arch} initrd=harvester-${version}-initrd-${arch} ip=dhcp net.ifnames=1 rd.cos.disable rd.noverifyssl BOOTIF={{ .MacAddress }} root=live:${base}/harvester-${version}-rootfs-${arch}.squashfs console=tty1 harvester.install.automatic=true boot_cmd='echo include_ping_test=yes >> /etc/conf.d/net-online' harvester.install.config_url={{ .HegelEndpoint }} {{if gt .VlanID 1}}ifname=netboot:{{ .MacAddress }} vlan=vlan{{ .VlanID }}:netboot {{end}}
kernel ${base}/harvester-${version}-vmlinuz-${arch} initrd=harvester-${version}-initrd-${arch} ip={{ .IP }}::{{ .Gateway }}:{{ .Netmask }}::netboot:off net.ifnames=1 rd.cos.disable rd.noverifyssl BOOTIF={{ .MacAddress }} ifname=netboot:{{ .MacAddress }} root=live:${base}/harvester-${version}-rootfs-${arch}.squashfs console=tty1 harvester.install.automatic=true boot_cmd='echo include_ping_test=yes >> /etc/conf.d/net-online' harvester.install.config_url={{ .HegelEndpoint }} {{if gt .VlanID 1}}vlan=vlan{{ .VlanID }}:netboot {{end}}
initrd ${base}/harvester-${version}-initrd-${arch}
Comment on lines 248 to 250

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

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

generateIPXEScript now requires IP/netmask/gateway and always emits a static ip=...:off kernel parameter. If any of these fields are empty (e.g. unexpected inventory status/pool status), the generated kernel cmdline will be malformed and can break provisioning. Consider validating these inputs and falling back to the previous ip=dhcp behavior when they are not all set.

Copilot uses AI. Check for mistakes.
boot
`
Expand Down
2 changes: 1 addition & 1 deletion pkg/tink/tink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func Test_GenerateWorkflow(t *testing.T) {

func Test_generateIPXEScript(t *testing.T) {
assert := require.New(t)
_, err := generateIPXEScript("v1.1.3", "http://imagestore/iso", "hegelEndpoint", "ab:cd:ef:gh:ij", "amd64", 1)
_, err := generateIPXEScript("v1.1.3", "http://imagestore/iso", "hegelEndpoint", "ab:cd:ef:gh:ij", "amd64", 1, "192.168.1.101", "255.255.255.0", "192.168.1.1")
assert.NoError(err, "expect no error during generation of ipxe script")
Comment on lines +274 to 275

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

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

The unit test only asserts that generateIPXEScript returns no error, but it doesn’t verify the new behavior (static addressing params and ifname=netboot mapping) in the generated script. Adding assertions for the rendered kernel line would prevent regressions in the new workaround logic.

Suggested change
_, err := generateIPXEScript("v1.1.3", "http://imagestore/iso", "hegelEndpoint", "ab:cd:ef:gh:ij", "amd64", 1, "192.168.1.101", "255.255.255.0", "192.168.1.1")
assert.NoError(err, "expect no error during generation of ipxe script")
script, err := generateIPXEScript("v1.1.3", "http://imagestore/iso", "hegelEndpoint", "ab:cd:ef:gh:ij", "amd64", 1, "192.168.1.101", "255.255.255.0", "192.168.1.1")
assert.NoError(err, "expect no error during generation of ipxe script")
assert.Contains(script, "ifname=netboot", "expected kernel params to include ifname=netboot mapping")
assert.Contains(script, "192.168.1.101", "expected kernel params to include static IP address")
assert.Contains(script, "255.255.255.0", "expected kernel params to include subnet mask")
assert.Contains(script, "192.168.1.1", "expected kernel params to include gateway")

Copilot uses AI. Check for mistakes.
}

Expand Down
Loading