From 7ffbdcadd22b3ceddc7f767310c7473388465341 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 11 Aug 2016 23:09:50 -0700 Subject: [PATCH] pixiecore: Implement a static booter for simple boot cases. --- pixiecore/booters.go | 107 ++++++++++++++++++++++++++++++++ pixiecore/cli/cli.go | 12 +++- pixiecore/cli/temptestbooter.go | 60 ------------------ 3 files changed, 116 insertions(+), 63 deletions(-) create mode 100644 pixiecore/booters.go delete mode 100644 pixiecore/cli/temptestbooter.go diff --git a/pixiecore/booters.go b/pixiecore/booters.go new file mode 100644 index 0000000..002f7e4 --- /dev/null +++ b/pixiecore/booters.go @@ -0,0 +1,107 @@ +// 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 ( + "fmt" + "io" + "net/http" + "os" + "strconv" + "strings" +) + +// StaticBooter boots all machines with the same Spec. +// +// IDs in spec should be either local file paths, or HTTP/HTTPS URLs. +func StaticBooter(spec *Spec) Booter { + ret := &staticBooter{ + kernel: string(spec.Kernel), + spec: &Spec{ + Kernel: "kernel", + Cmdline: map[string]interface{}{}, + Message: spec.Message, + }, + } + for i, initrd := range spec.Initrd { + ret.initrd = append(ret.initrd, string(initrd)) + ret.spec.Initrd = append(ret.spec.Initrd, ID(fmt.Sprintf("initrd-%d", i))) + } + for k, v := range spec.Cmdline { + if id, ok := v.(ID); ok { + ret.otherIDs = append(ret.otherIDs, string(id)) + ret.spec.Cmdline[k] = ID(fmt.Sprintf("other-%d", len(ret.otherIDs)-1)) + } else { + ret.spec.Cmdline[k] = v + } + } + + return ret +} + +type staticBooter struct { + kernel string + initrd []string + otherIDs []string + + spec *Spec +} + +func (s *staticBooter) BootSpec(m Machine) (*Spec, error) { + return s.spec, nil +} + +func (s *staticBooter) serveFile(path string) (io.ReadCloser, error) { + if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") { + resp, err := http.Get(path) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + resp.Body.Close() + return nil, fmt.Errorf("%s: %s", path, http.StatusText(resp.StatusCode)) + } + return resp.Body, nil + } + return os.Open(path) +} + +func (s *staticBooter) ReadBootFile(id ID) (io.ReadCloser, error) { + path := string(id) + switch { + case path == "kernel": + return s.serveFile(s.kernel) + + case strings.HasPrefix(path, "initrd-"): + i, err := strconv.Atoi(string(path[7:])) + if err != nil || i < 0 || i >= len(s.initrd) { + return nil, fmt.Errorf("no file with ID %q", id) + } + return s.serveFile(s.initrd[i]) + + case strings.HasPrefix(path, "other-"): + i, err := strconv.Atoi(string(path[6:])) + if err != nil || i < 0 || i >= len(s.otherIDs) { + return nil, fmt.Errorf("no file with ID %q", id) + } + return s.serveFile(s.otherIDs[i]) + } + + return nil, fmt.Errorf("no file with ID %q", id) +} + +func (s *staticBooter) WriteBootFile(ID, io.Reader) error { + return nil +} diff --git a/pixiecore/cli/cli.go b/pixiecore/cli/cli.go index e4847f0..4e78158 100644 --- a/pixiecore/cli/cli.go +++ b/pixiecore/cli/cli.go @@ -28,9 +28,15 @@ import ( // Takes a map of ipxe bootloader binaries for various architectures. func CLI(ipxe map[pixiecore.Firmware][]byte) { s := &pixiecore.Server{ - Booter: tinycore{}, - Ipxe: ipxe, - Log: func(msg string) { fmt.Println(msg) }, + Booter: pixiecore.StaticBooter(&pixiecore.Spec{ + Kernel: pixiecore.ID("http://tinycorelinux.net/7.x/x86/release/distribution_files/vmlinuz64"), + Initrd: []pixiecore.ID{ + "http://tinycorelinux.net/7.x/x86/release/distribution_files/rootfs.gz", + "http://tinycorelinux.net/7.x/x86/release/distribution_files/modules64.gz", + }, + }), + Ipxe: ipxe, + Log: func(msg string) { fmt.Println(msg) }, } fmt.Println(s.Serve()) diff --git a/pixiecore/cli/temptestbooter.go b/pixiecore/cli/temptestbooter.go deleted file mode 100644 index a9f323c..0000000 --- a/pixiecore/cli/temptestbooter.go +++ /dev/null @@ -1,60 +0,0 @@ -// 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 cli - -import ( - "fmt" - "io" - "net/http" - - "go.universe.tf/netboot/pixiecore" -) - -// This is just a very temporary test booter that boots everything -// into tinycore linux, always. - -type tinycore struct{} - -func (tinycore) BootSpec(m pixiecore.Machine) (*pixiecore.Spec, error) { - return &pixiecore.Spec{ - Kernel: pixiecore.ID("k"), - Initrd: []pixiecore.ID{"1", "2"}, - }, nil -} - -func (tinycore) ReadBootFile(id pixiecore.ID) (io.ReadCloser, error) { - var url string - switch id { - case "k": - url = "http://tinycorelinux.net/7.x/x86/release/distribution_files/vmlinuz64" - case "1": - url = "http://tinycorelinux.net/7.x/x86/release/distribution_files/rootfs.gz" - case "2": - url = "http://tinycorelinux.net/7.x/x86/release/distribution_files/modules64.gz" - } - resp, err := http.Get(url) - if err != nil { - return nil, err - } - if resp.StatusCode != http.StatusOK { - resp.Body.Close() - return nil, fmt.Errorf("%s: %s", url, http.StatusText(resp.StatusCode)) - } - return resp.Body, nil -} - -func (tinycore) WriteBootFile(id pixiecore.ID, body io.Reader) error { - return nil -}