Skip to content

Commit

Permalink
feat: extend information printed in the iPXE script, add retries
Browse files Browse the repository at this point in the history
With this change, iPXE now prints information about available network
interfaces and configured IP after DHCP.

It should also retry DHCP but it's hard to test in my environment.

Also different interface should be tried if loading `/ipxe` script
fails.

Example:

```
net0: 4e:65:61:9e:84:a4 using undionly on 0000:00:02.0 (closed)
  [Link:up, TX:0 TXE:1 RX:0 RXE:0]
  [TXE: 1 x "Network unreachable (http://ipxe.org/28086011)"]
Configuring (net0 4e:65:61:9e:84:a4)...... ok
net0: 172.25.0.3/255.255.255.0 gw 172.25.0.1
http://172.24.0.2:8081/ipxe... ok
/env/agent-amd64/vmlinuz... ok
```

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
  • Loading branch information
smira committed Dec 9, 2021
1 parent 4cfdeda commit 1bbe3be
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 12 deletions.
58 changes: 52 additions & 6 deletions app/sidero-controller-manager/internal/ipxe/ipxe_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,57 @@ const bootFile = `#!ipxe
chain ipxe?uuid=${uuid}&mac=${mac:hexhyp}&domain=${domain}&hostname=${hostname}&serial=${serial}&arch=${buildarch}
`

// bootTemplate is embedded into iPXE binary when that binary is sent to the node.
//
// bootTemplate should be kept in sync with the bootFile above.
var bootTemplate = template.Must(template.New("iPXE embedded").Parse(`dhcp
chain http://{{ .Endpoint }}:{{ .Port }}/ipxe?uuid=${uuid}&mac=${mac:hexhyp}&domain=${domain}&hostname=${hostname}&serial=${serial}&arch=${buildarch}
// BootTemplate is embedded into iPXE binary when that binary is sent to the node.
var BootTemplate = template.Must(template.New("iPXE embedded").Parse(`
prompt --key 0x02 --timeout 2000 Press Ctrl-B for the iPXE command line... && shell ||
# print interfaces
ifstat
# retry 10 times overall
set attempts:int32 10
set x:int32 0
:retry_loop
set idx:int32 0
:loop
# try DHCP on each available interface
isset ${net${idx}/mac} || goto exhausted
ifclose
dhcp net${idx} && goto boot
:next_iface
inc idx && goto loop
:boot
# attempt boot, if fails try next iface
route
chain http://{{ .Endpoint }}:{{ .Port }}/ipxe?uuid=${uuid}&mac=${net${idx}/mac:hexhyp}&domain=${domain}&hostname=${hostname}&serial=${serial}&arch=${buildarch} || goto next_iface
:exhausted
echo
echo Failed to iPXE boot successfully via all interfaces
iseq ${x} ${attempts} && goto fail ||
echo Retrying...
echo
inc x
goto retry_loop
:fail
echo
echo Failed to get a valid response after ${attempts} attempts
echo
echo Rebooting in 5 seconds...
sleep 5
reboot
`))

// ipxeTemplate is returned as response to `chain` request from the bootFile/bootTemplate to boot actual OS (or Sidero agent).
Expand Down Expand Up @@ -194,7 +240,7 @@ func RegisterIPXE(mux *http.ServeMux, endpoint string, port int, args string, bo

var embeddedScriptBuf bytes.Buffer

if err := bootTemplate.Execute(&embeddedScriptBuf, map[string]string{
if err := BootTemplate.Execute(&embeddedScriptBuf, map[string]string{
"Endpoint": apiEndpoint,
"Port": strconv.Itoa(iPXEPort),
}); err != nil {
Expand Down
27 changes: 21 additions & 6 deletions app/sidero-controller-manager/internal/ipxe/ipxe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,26 @@

package ipxe_test

import "testing"
import (
"bytes"
"testing"

func TestEmpty(t *testing.T) {
// added for accurate coverage estimation
//
// please remove it once any unit-test is added
// for this package
"github.com/stretchr/testify/assert"

"github.com/talos-systems/sidero/app/sidero-controller-manager/internal/ipxe"
)

func TestEmbeddedLength(t *testing.T) {
var buf bytes.Buffer

assert.NoError(t, ipxe.BootTemplate.Execute(&buf, struct {
Endpoint string
Port string
}{ // use bigger values here to get maximum length of the script
Endpoint: "[2001:470:6d:30e:e5b8:903e:3701:7332]",
Port: "12345",
}))

// iPXE script should fit length of the reserved space in the iPXE binary
assert.Less(t, buf.Len(), 1000)
}

0 comments on commit 1bbe3be

Please sign in to comment.