mirror of
https://github.com/danderson/netboot.git
synced 2025-08-07 15:17:15 +02:00
201 lines
6.3 KiB
Go
201 lines
6.3 KiB
Go
// Copyright 2016 Google Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package pixiecore
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
type booterFunc func(Machine) (*Spec, error)
|
|
|
|
func (b booterFunc) BootSpec(m Machine) (*Spec, error) { return b(m) }
|
|
func (b booterFunc) ReadBootFile(id ID) (io.ReadCloser, int64, error) {
|
|
return nil, -1, errors.New("no")
|
|
}
|
|
func (b booterFunc) WriteBootFile(id ID, r io.Reader) error { return errors.New("no") }
|
|
|
|
func TestIpxe(t *testing.T) {
|
|
booter := func(m Machine) (*Spec, error) {
|
|
return &Spec{
|
|
Kernel: ID(fmt.Sprintf("k-%s-%d", m.MAC, m.Arch)),
|
|
Initrd: []ID{
|
|
ID(fmt.Sprintf("i1-%s-%d", m.MAC, m.Arch)),
|
|
ID(fmt.Sprintf("i2-%s-%d", m.MAC, m.Arch)),
|
|
},
|
|
Cmdline: fmt.Sprintf(`thing={{ ID "f-%s-%d" }} foo=bar`, m.MAC, m.Arch),
|
|
Message: "Hello from the test!",
|
|
}, nil
|
|
}
|
|
log := func(subsystem, msg string) { t.Logf("[%s] %s", subsystem, msg) }
|
|
s := &Server{
|
|
Booter: booterFunc(booter),
|
|
Log: log,
|
|
Debug: log,
|
|
events: make(map[string][]machineEvent),
|
|
}
|
|
|
|
// Successful boot
|
|
rr := httptest.NewRecorder()
|
|
req, err := http.NewRequest("GET", "/_/ipxe?mac=01:02:03:04:05:06&arch=0", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing ipxe request: %s", err)
|
|
}
|
|
req.Host = "localhost:1234"
|
|
s.handleIpxe(rr, req)
|
|
|
|
if rr.Code != 200 {
|
|
t.Fatalf("Got HTTP %d from request, expected 200", rr.Code)
|
|
}
|
|
|
|
expected := `#!ipxe
|
|
kernel --name kernel http://localhost:1234/_/file?name=k-01%3A02%3A03%3A04%3A05%3A06-0&type=kernel&mac=01%3A02%3A03%3A04%3A05%3A06
|
|
initrd --name initrd0 http://localhost:1234/_/file?name=i1-01%3A02%3A03%3A04%3A05%3A06-0&type=initrd&mac=01%3A02%3A03%3A04%3A05%3A06
|
|
initrd --name initrd1 http://localhost:1234/_/file?name=i2-01%3A02%3A03%3A04%3A05%3A06-0&type=initrd&mac=01%3A02%3A03%3A04%3A05%3A06
|
|
imgfetch --name ready http://localhost:1234/_/booting?mac=01%3A02%3A03%3A04%3A05%3A06 ||
|
|
imgfree ready ||
|
|
boot kernel initrd=initrd0 initrd=initrd1 thing=http://localhost:1234/_/file?name=f-01%3A02%3A03%3A04%3A05%3A06-0 foo=bar
|
|
`
|
|
if rr.Body.String() != expected {
|
|
t.Fatalf("Wrong iPXE script\nwant: %s\ngot: %s", expected, rr.Body.String())
|
|
}
|
|
|
|
// Another successful boot
|
|
rr = httptest.NewRecorder()
|
|
req, err = http.NewRequest("GET", "/_/ipxe?mac=fe:fe:fe:fe:fe:fe&arch=1", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing ipxe request: %s", err)
|
|
}
|
|
req.Host = "localhost:1234"
|
|
s.handleIpxe(rr, req)
|
|
|
|
if rr.Code != 200 {
|
|
t.Fatalf("Got HTTP %d from request, expected 200", rr.Code)
|
|
}
|
|
|
|
expected = `#!ipxe
|
|
kernel --name kernel http://localhost:1234/_/file?name=k-fe%3Afe%3Afe%3Afe%3Afe%3Afe-1&type=kernel&mac=fe%3Afe%3Afe%3Afe%3Afe%3Afe
|
|
initrd --name initrd0 http://localhost:1234/_/file?name=i1-fe%3Afe%3Afe%3Afe%3Afe%3Afe-1&type=initrd&mac=fe%3Afe%3Afe%3Afe%3Afe%3Afe
|
|
initrd --name initrd1 http://localhost:1234/_/file?name=i2-fe%3Afe%3Afe%3Afe%3Afe%3Afe-1&type=initrd&mac=fe%3Afe%3Afe%3Afe%3Afe%3Afe
|
|
imgfetch --name ready http://localhost:1234/_/booting?mac=fe%3Afe%3Afe%3Afe%3Afe%3Afe ||
|
|
imgfree ready ||
|
|
boot kernel initrd=initrd0 initrd=initrd1 thing=http://localhost:1234/_/file?name=f-fe%3Afe%3Afe%3Afe%3Afe%3Afe-1 foo=bar
|
|
`
|
|
if rr.Body.String() != expected {
|
|
t.Fatalf("Wrong iPXE script\nwant: %s\ngot: %s", expected, rr.Body.String())
|
|
}
|
|
|
|
// Invalid requests
|
|
for _, url := range []string{
|
|
"/_/ipxe?mac=any&arch=1",
|
|
"/_/ipxe?mac=fe:fe:fe:fe:fe:fe&arch=x86",
|
|
"/_/ipxe?mac=fe:fe:fe:fe:fe:fe&arch=42",
|
|
} {
|
|
rr = httptest.NewRecorder()
|
|
req, err = http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing ipxe request: %s", err)
|
|
}
|
|
s.handleIpxe(rr, req)
|
|
|
|
if rr.Code != 400 {
|
|
t.Fatalf("Got HTTP %d from request, expected 400", rr.Code)
|
|
}
|
|
}
|
|
|
|
// Refused boot (no error)
|
|
booter = func(m Machine) (*Spec, error) { return nil, nil }
|
|
s.Booter = booterFunc(booter)
|
|
rr = httptest.NewRecorder()
|
|
req, err = http.NewRequest("GET", "/_/ipxe?mac=fe:fe:fe:fe:fe:fe&arch=1", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing ipxe request: %s", err)
|
|
}
|
|
s.handleIpxe(rr, req)
|
|
|
|
if rr.Code != 404 {
|
|
t.Fatalf("Got HTTP %d from request, expected 404", rr.Code)
|
|
}
|
|
|
|
// Booter error
|
|
booter = func(m Machine) (*Spec, error) { return nil, errors.New("boom") }
|
|
s.Booter = booterFunc(booter)
|
|
rr = httptest.NewRecorder()
|
|
req, err = http.NewRequest("GET", "/_/ipxe?mac=fe:fe:fe:fe:fe:fe&arch=1", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing ipxe request: %s", err)
|
|
}
|
|
s.handleIpxe(rr, req)
|
|
|
|
if rr.Code != 500 {
|
|
t.Fatalf("Got HTTP %d from request, expected 500", rr.Code)
|
|
}
|
|
}
|
|
|
|
type readBootFile string
|
|
|
|
func (b readBootFile) BootSpec(m Machine) (*Spec, error) { return nil, nil }
|
|
func (b readBootFile) ReadBootFile(id ID) (io.ReadCloser, int64, error) {
|
|
d := fmt.Sprintf("%s %s", id, b)
|
|
return ioutil.NopCloser(bytes.NewBuffer([]byte(d))), int64(len(d)), nil
|
|
}
|
|
func (b readBootFile) WriteBootFile(id ID, r io.Reader) error { return errors.New("no") }
|
|
|
|
func TestFile(t *testing.T) {
|
|
log := func(subsystem, msg string) { t.Logf("[%s] %s", subsystem, msg) }
|
|
s := &Server{
|
|
Booter: readBootFile("stuff"),
|
|
Log: log,
|
|
Debug: log,
|
|
}
|
|
rr := httptest.NewRecorder()
|
|
req, err := http.NewRequest("GET", "/_/file?name=test", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing file request: %s", err)
|
|
}
|
|
s.handleFile(rr, req)
|
|
|
|
if rr.Code != 200 {
|
|
t.Fatalf("Got HTTP %d from request, expected 200", rr.Code)
|
|
}
|
|
|
|
expected := "test stuff"
|
|
if rr.Body.String() != expected {
|
|
t.Fatalf("Wrong file contents, want %q, got %q", expected, rr.Body.Bytes())
|
|
}
|
|
|
|
rr = httptest.NewRecorder()
|
|
req, err = http.NewRequest("GET", "/_/file?name=quux", nil)
|
|
if err != nil {
|
|
t.Fatalf("Constructing file request: %s", err)
|
|
}
|
|
s.handleFile(rr, req)
|
|
|
|
if rr.Code != 200 {
|
|
t.Fatalf("Got HTTP %d from request, expected 200", rr.Code)
|
|
}
|
|
|
|
expected = "quux stuff"
|
|
if rr.Body.String() != expected {
|
|
t.Fatalf("Wrong file contents, want %q, got %q", expected, rr.Body.Bytes())
|
|
}
|
|
}
|