bootv2 support
This commit is contained in:
140
cmd/dkl-local-server/bootv2.go
Normal file
140
cmd/dkl-local-server/bootv2.go
Normal file
@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"novit.tech/direktil/pkg/cpiocat"
|
||||
)
|
||||
|
||||
func renderBootstrapConfig(w http.ResponseWriter, r *http.Request, ctx *renderContext, asJson bool) (err error) {
|
||||
log.Printf("sending bootstrap config for %q", ctx.Host.Name)
|
||||
|
||||
_, cfg, err := ctx.BootstrapConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if asJson {
|
||||
err = json.NewEncoder(w).Encode(cfg)
|
||||
} else {
|
||||
err = yaml.NewEncoder(w).Encode(cfg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildInitrdV2(out io.Writer, ctx *renderContext) (err error) {
|
||||
_, cfg, err := ctx.Config()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cat := cpiocat.New(out)
|
||||
|
||||
// initrd
|
||||
initrdPath, err := ctx.distFetch("initrd", "2.0.0" /* FIXME */)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cat.AppendArchFile(initrdPath)
|
||||
|
||||
// embedded layers (modules)
|
||||
for _, layer := range cfg.Layers {
|
||||
switch layer {
|
||||
case "modules":
|
||||
|
||||
layerVersion := ctx.Host.Versions[layer]
|
||||
modulesPath, err := ctx.distFetch("layers", layer, layerVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cat.AppendFile(modulesPath, "modules.sqfs")
|
||||
}
|
||||
}
|
||||
|
||||
// config
|
||||
cfgBytes, _, err := ctx.BootstrapConfig()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cat.AppendBytes(cfgBytes, "config.yaml", 0600)
|
||||
|
||||
// ssh keys
|
||||
// FIXME we want a bootstrap-stage key instead of the real host key
|
||||
cat.AppendBytes(cfg.FileContent("/etc/ssh/ssh_host_rsa_key"), "id_rsa", 0600)
|
||||
|
||||
return cat.Close()
|
||||
}
|
||||
|
||||
func buildBootstrap(out io.Writer, ctx *renderContext) (err error) {
|
||||
arch := tar.NewWriter(out)
|
||||
defer arch.Close()
|
||||
|
||||
// config
|
||||
cfgBytes, cfg, err := ctx.Config()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = arch.WriteHeader(&tar.Header{Name: "config.yaml", Size: int64(len(cfgBytes))})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = arch.Write(cfgBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// layers
|
||||
for _, layer := range cfg.Layers {
|
||||
if layer == "modules" {
|
||||
continue // modules are with the kernel in boot v2
|
||||
}
|
||||
|
||||
layerVersion := ctx.Host.Versions[layer]
|
||||
if layerVersion == "" {
|
||||
return fmt.Errorf("layer %q not mapped to a version", layer)
|
||||
}
|
||||
|
||||
outPath, err := ctx.distFetch("layers", layer, layerVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Open(outPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = arch.WriteHeader(&tar.Header{
|
||||
Name: layer + ".fs",
|
||||
Size: stat.Size(),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(arch, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -8,7 +8,8 @@ import (
|
||||
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"novit.nc/direktil/pkg/config"
|
||||
|
||||
"novit.tech/direktil/pkg/config"
|
||||
)
|
||||
|
||||
var templateFuncs = map[string]interface{}{
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"flag"
|
||||
"path/filepath"
|
||||
|
||||
"novit.nc/direktil/pkg/localconfig"
|
||||
"novit.tech/direktil/pkg/localconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -8,9 +8,10 @@ import (
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
swaggerui "github.com/mcluseau/go-swagger-ui"
|
||||
"novit.nc/direktil/pkg/cas"
|
||||
|
||||
"novit.nc/direktil/local-server/pkg/apiutils"
|
||||
"novit.tech/direktil/pkg/cas"
|
||||
|
||||
"novit.tech/direktil/local-server/pkg/apiutils"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -15,8 +15,10 @@ import (
|
||||
restful "github.com/emicklei/go-restful"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"novit.nc/direktil/pkg/config"
|
||||
"novit.nc/direktil/pkg/localconfig"
|
||||
"novit.tech/direktil/pkg/config"
|
||||
"novit.tech/direktil/pkg/localconfig"
|
||||
|
||||
bsconfig "novit.tech/direktil/pkg/bootstrapconfig"
|
||||
)
|
||||
|
||||
var cmdlineParam = restful.QueryParameter("cmdline", "Linux kernel cmdline addition")
|
||||
@ -89,9 +91,37 @@ func newRenderContext(host *localconfig.Host, cfg *localconfig.Config) (ctx *ren
|
||||
}
|
||||
|
||||
func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
|
||||
ba, err = ctx.render(ctx.Host.Config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfg = &config.Config{}
|
||||
if err = yaml.Unmarshal(ba, cfg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *renderContext) BootstrapConfig() (ba []byte, cfg *bsconfig.Config, err error) {
|
||||
ba, err = ctx.render(ctx.Host.BootstrapConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfg = &bsconfig.Config{}
|
||||
if err = yaml.Unmarshal(ba, cfg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctx *renderContext) render(templateText string) (ba []byte, err error) {
|
||||
tmpl, err := template.New(ctx.Host.Name + "/config").
|
||||
Funcs(templateFuncs).
|
||||
Parse(ctx.Host.Config)
|
||||
Parse(templateText)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
@ -110,13 +140,6 @@ func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
|
||||
}
|
||||
|
||||
ba = buf.Bytes()
|
||||
|
||||
cfg = &config.Config{}
|
||||
|
||||
if err = yaml.Unmarshal(buf.Bytes(), cfg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
|
||||
"novit.nc/direktil/pkg/localconfig"
|
||||
"novit.tech/direktil/pkg/localconfig"
|
||||
)
|
||||
|
||||
func wsListClusters(req *restful.Request, resp *restful.Response) {
|
||||
|
@ -8,8 +8,9 @@ import (
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
|
||||
"novit.nc/direktil/local-server/pkg/mime"
|
||||
"novit.nc/direktil/pkg/localconfig"
|
||||
"novit.tech/direktil/pkg/localconfig"
|
||||
|
||||
"novit.tech/direktil/local-server/pkg/mime"
|
||||
)
|
||||
|
||||
var trustXFF = flag.Bool("trust-xff", true, "Trust the X-Forwarded-For header")
|
||||
@ -74,6 +75,22 @@ func (ws *wsHost) register(rws *restful.WebService, alterRB func(*restful.RouteB
|
||||
b("initrd").
|
||||
Produces(mime.OCTET).
|
||||
Doc("Get the " + ws.hostDoc + "'s initial RAM disk (ie: for netboot)"),
|
||||
|
||||
// boot v2
|
||||
// - bootstrap config
|
||||
b("bootstrap-config").
|
||||
Produces(mime.YAML).
|
||||
Doc("Get the " + ws.hostDoc + "'s bootstrap configuration"),
|
||||
b("bootstrap-config.json").
|
||||
Doc("Get the " + ws.hostDoc + "'s bootstrap configuration (as JSON)"),
|
||||
// - initrd
|
||||
b("initrd-v2").
|
||||
Produces(mime.OCTET).
|
||||
Doc("Get the " + ws.hostDoc + "'s initial RAM disk (v2)"),
|
||||
// - bootstrap
|
||||
b("bootstrap.tar").
|
||||
Produces(mime.TAR).
|
||||
Doc("Get the " + ws.hostDoc + "'s bootstrap seed archive"),
|
||||
} {
|
||||
alterRB(rb)
|
||||
rws.Route(rb)
|
||||
@ -161,6 +178,16 @@ func renderHost(w http.ResponseWriter, r *http.Request, what string, host *local
|
||||
case "boot.img.lz4":
|
||||
err = renderCtx(w, r, ctx, what, buildBootImgLZ4)
|
||||
|
||||
// boot v2
|
||||
case "bootstrap-config":
|
||||
err = renderBootstrapConfig(w, r, ctx, false)
|
||||
case "bootstrap-config.json":
|
||||
err = renderBootstrapConfig(w, r, ctx, true)
|
||||
case "initrd-v2":
|
||||
err = renderCtx(w, r, ctx, what, buildInitrdV2)
|
||||
case "bootstrap.tar":
|
||||
err = renderCtx(w, r, ctx, what, buildBootstrap)
|
||||
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
@ -10,8 +10,9 @@ import (
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
|
||||
"novit.nc/direktil/local-server/pkg/mime"
|
||||
"novit.nc/direktil/pkg/localconfig"
|
||||
"novit.tech/direktil/pkg/localconfig"
|
||||
|
||||
"novit.tech/direktil/local-server/pkg/mime"
|
||||
)
|
||||
|
||||
func registerWS(rest *restful.Container) {
|
||||
|
Reference in New Issue
Block a user