diff --git a/Dockerfile b/Dockerfile index 01a8cff..bb88d7e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ from novit.tech/direktil/dkl:bbea9b9 as dkl # ------------------------------------------------------------------------ -from golang:1.25.0-trixie as build +from golang:1.25.5-trixie as build run apt-get update && apt-get install -y git diff --git a/cmd/dkl-dir2config/render-context.go b/cmd/dkl-dir2config/render-context.go index b6e18cc..8c33dda 100644 --- a/cmd/dkl-dir2config/render-context.go +++ b/cmd/dkl-dir2config/render-context.go @@ -224,6 +224,7 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]any { if err != nil { return } + reqJson := cleanJsonObject(buf.String()) key := name if req.PerHost { @@ -236,11 +237,11 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]any { dir := "/etc/tls/" + name s = fmt.Sprintf("{{ %s %q %q %q %q %q %q %q }}", funcName, - dir, cluster, req.CA, key, req.Profile, req.Label, buf.String()) + dir, cluster, req.CA, key, req.Profile, req.Label, reqJson) default: s = fmt.Sprintf("{{ %s %q %q %q %q %q %q }}", funcName, - cluster, req.CA, key, req.Profile, req.Label, buf.String()) + cluster, req.CA, key, req.Profile, req.Label, reqJson) } return } @@ -281,11 +282,11 @@ func (ctx *renderContext) templateFuncs(ctxMap map[string]any) map[string]any { }, "ssh_user_ca": func(path string) (s string) { - return fmt.Sprintf("{{ ssh_user_ca %q %q}}", + return fmt.Sprintf("{{ ssh_user_ca %q %q }}", path, cluster) }, "ssh_host_keys": func(dir string) (s string) { - return fmt.Sprintf("{{ ssh_host_keys %q %q \"\"}}", + return fmt.Sprintf("{{ ssh_host_keys %q %q \"\" }}", dir, cluster) }, "host_download_token": func() (s string) { diff --git a/cmd/dkl-dir2config/render-host.go b/cmd/dkl-dir2config/render-host.go index 1487db5..cbda7c8 100644 --- a/cmd/dkl-dir2config/render-host.go +++ b/cmd/dkl-dir2config/render-host.go @@ -29,7 +29,7 @@ func (ctx *renderContext) renderStaticPods() (pods []namePod) { for n := 0; ; n++ { str := buf.String() - podMap := map[string]interface{}{} + podMap := map[string]any{} err := dec.Decode(podMap) if err == io.EOF { @@ -46,7 +46,7 @@ func (ctx *renderContext) renderStaticPods() (pods []namePod) { log.Fatalf("static pod %d: no metadata\n%s", n, buf.String()) } - md := podMap["metadata"].(map[interface{}]interface{}) + md := podMap["metadata"].(map[any]any) namespace := md["namespace"].(string) name := md["name"].(string) diff --git a/cmd/dkl-dir2config/utils.go b/cmd/dkl-dir2config/utils.go new file mode 100644 index 0000000..a95c383 --- /dev/null +++ b/cmd/dkl-dir2config/utils.go @@ -0,0 +1,15 @@ +package main + +import ( + "encoding/json" + "fmt" +) + +func cleanJsonObject(raw string) string { + v := map[string]any{} + if err := json.Unmarshal([]byte(raw), &v); err != nil { + panic(fmt.Errorf("invalid json: %w\n%s", err, raw)) + } + clean, _ := json.Marshal(v) + return string(clean) +} diff --git a/cmd/dkl-local-server/ws-configs.go b/cmd/dkl-local-server/ws-configs.go index ff978c3..c2015f6 100644 --- a/cmd/dkl-local-server/ws-configs.go +++ b/cmd/dkl-local-server/ws-configs.go @@ -1,20 +1,32 @@ package main import ( + "bytes" "compress/gzip" "io" "os" "path/filepath" restful "github.com/emicklei/go-restful" + "gopkg.in/yaml.v2" + "m.cluseau.fr/go/httperr" + "novit.tech/direktil/pkg/localconfig" ) func wsUploadConfig(req *restful.Request, resp *restful.Response) { - body := req.Request.Body + cfg := &localconfig.Config{} + if err := req.ReadEntity(cfg); err != nil { + wsError(resp, httperr.BadRequest(err.Error())) + return + } - err := writeNewConfig(body) - body.Close() + cfgBytes, err := yaml.Marshal(cfg) + if err != nil { + wsError(resp, err) + return + } + err = writeNewConfig(cfgBytes) if err != nil { wsError(resp, err) return @@ -23,7 +35,7 @@ func wsUploadConfig(req *restful.Request, resp *restful.Response) { resp.WriteEntity(true) } -func writeNewConfig(reader io.Reader) (err error) { +func writeNewConfig(cfgBytes []byte) (err error) { out, err := os.CreateTemp(*dataDir, ".config-upload") if err != nil { return @@ -31,7 +43,7 @@ func writeNewConfig(reader io.Reader) (err error) { defer os.Remove(out.Name()) - _, err = io.Copy(out, reader) + _, err = io.Copy(out, bytes.NewReader(cfgBytes)) out.Close() if err != nil { return diff --git a/cmd/dkl-local-server/ws.go b/cmd/dkl-local-server/ws.go index 9816494..bec8a7f 100644 --- a/cmd/dkl-local-server/ws.go +++ b/cmd/dkl-local-server/ws.go @@ -11,6 +11,7 @@ import ( cfsslconfig "github.com/cloudflare/cfssl/config" "github.com/emicklei/go-restful" + "gopkg.in/yaml.v2" "m.cluseau.fr/go/httperr" "novit.tech/direktil/pkg/localconfig" @@ -75,7 +76,7 @@ func registerWS(rest *restful.Container) { // - configs API ws.Route(ws.POST("/configs").To(wsUploadConfig). - Consumes(mime.YAML).Param(ws.BodyParameter("config", "The new full configuration")). + Consumes(mime.YAML, mime.JSON).Param(ws.BodyParameter("config", "The new full configuration")). Produces(mime.JSON).Writes(true). Doc("Upload a new current configuration, archiving the previous one")) @@ -307,3 +308,26 @@ func wsRender(resp *restful.Response, sslCfg *cfsslconfig.Config, tmplStr string return } } + +func init() { + restful.RegisterEntityAccessor(mime.YAML, yamlEntityAccessor{}) +} + +type yamlEntityAccessor struct{} + +var _ restful.EntityReaderWriter = yamlEntityAccessor{} + +func (_ yamlEntityAccessor) Read(req *restful.Request, v any) error { + decoder := yaml.NewDecoder(req.Request.Body) + return decoder.Decode(v) +} +func (_ yamlEntityAccessor) Write(resp *restful.Response, status int, v any) error { + if v == nil { + resp.WriteHeader(status) + // do not write a nil representation + return nil + } + resp.Header().Set("Content-Type", mime.YAML) + resp.WriteHeader(status) + return yaml.NewEncoder(resp.ResponseWriter).Encode(v) +} diff --git a/install-on-metal.sh b/install-on-metal.sh index 99e7c2a..02b89a9 100755 --- a/install-on-metal.sh +++ b/install-on-metal.sh @@ -8,14 +8,14 @@ dev=$1 set -ex +zcat boot.img.gz | dd of=$dev + apk add sgdisk [[ $dev =~ nvme ]] && devp=${dev}p || devp=${dev} -zcat boot.img.gz | dd of=$dev - sgdisk --move-second-header --new=3:0:0 $dev pvcreate ${devp}3 diff --git a/pkg/clustersconfig/dir.go b/pkg/clustersconfig/dir.go index 143fff9..3a4ca5b 100644 --- a/pkg/clustersconfig/dir.go +++ b/pkg/clustersconfig/dir.go @@ -2,7 +2,6 @@ package clustersconfig import ( "fmt" - "io/ioutil" "os" "path" "path/filepath" @@ -178,7 +177,7 @@ type dirStore struct { // listDir func (b *dirStore) listDir(prefix string) (subDirs []string, err error) { - entries, err := ioutil.ReadDir(filepath.Join(b.path, prefix)) + entries, err := os.ReadDir(filepath.Join(b.path, prefix)) if err != nil { return } @@ -226,7 +225,7 @@ func (b *dirStore) List(prefix string) ([]string, error) { // Load is part of the DataBackend interface func (b *dirStore) Get(key string) (ba []byte, err error) { - ba, err = ioutil.ReadFile(filepath.Join(b.path, filepath.Join(path.Split(key))+".yaml")) + ba, err = os.ReadFile(filepath.Join(b.path, filepath.Join(path.Split(key))+".yaml")) if os.IsNotExist(err) { return nil, nil }