forked from poseidon/matchbox
/
ipxe.go
53 lines (47 loc) · 1.42 KB
/
ipxe.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package http
import (
"bytes"
"fmt"
"net/http"
"text/template"
"golang.org/x/net/context"
)
const ipxeBootstrap = `#!ipxe
chain ipxe?uuid=${uuid}&mac=${net0/mac:hexhyp}&domain=${domain}&hostname=${hostname}&serial=${serial}
`
var ipxeTemplate = template.Must(template.New("iPXE config").Parse(`#!ipxe
kernel {{.Kernel}}{{range $key, $value := .Cmdline}} {{if $value}}{{$key}}={{$value}}{{else}}{{$key}}{{end}}{{end}}
initrd {{ range $element := .Initrd }}{{$element}} {{end}}
boot
`))
// ipxeInspect returns a handler that responds with the iPXE script to gather
// client machine data and chainload to the ipxeHandler.
func ipxeInspect() http.Handler {
fn := func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, ipxeBootstrap)
}
return http.HandlerFunc(fn)
}
// ipxeBoot returns a handler which renders the iPXE boot script for the
// requester.
func ipxeHandler() ContextHandler {
fn := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
profile, err := profileFromContext(ctx)
if err != nil {
http.NotFound(w, req)
return
}
var buf bytes.Buffer
err = ipxeTemplate.Execute(&buf, profile.Boot)
if err != nil {
log.Errorf("error rendering template: %v", err)
http.NotFound(w, req)
return
}
if _, err := buf.WriteTo(w); err != nil {
log.Errorf("error writing to response: %v", err)
w.WriteHeader(http.StatusInternalServerError)
}
}
return ContextHandlerFunc(fn)
}