fix: render template for addons and bootstrap pods

This commit is contained in:
Mikaël Cluseau 2019-12-26 11:10:23 +01:00
parent 49a16fe550
commit 1ee5d1c15a
4 changed files with 189 additions and 165 deletions

View File

@ -0,0 +1,168 @@
package main
import (
"encoding/json"
"fmt"
"log"
"path"
"github.com/cloudflare/cfssl/csr"
yaml "gopkg.in/yaml.v2"
"novit.nc/direktil/pkg/config"
)
var templateFuncs = map[string]interface{}{
"password": func(cluster, name string) (password string, err error) {
password = secretData.Password(cluster, name)
if len(password) == 0 {
err = fmt.Errorf("password %q not defined for cluster %q", name, cluster)
}
return
},
"token": func(cluster, name string) (s string, err error) {
return secretData.Token(cluster, name)
},
"ca_key": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
s = string(ca.Key)
return
},
"ca_crt": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
s = string(ca.Cert)
return
},
"ca_dir": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
dir := "/etc/tls-ca/" + name
return asYaml([]config.FileDef{
{
Path: path.Join(dir, "ca.crt"),
Mode: 0644,
Content: string(ca.Cert),
},
{
Path: path.Join(dir, "ca.key"),
Mode: 0600,
Content: string(ca.Key),
},
})
},
"tls_key": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
s = string(kc.Key)
return
},
"tls_crt": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
s = string(kc.Cert)
return
},
"tls_dir": func(dir, cluster, caName, name, profile, label, reqJson string) (s string, err error) {
ca, err := secretData.CA(cluster, caName)
if err != nil {
return
}
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
return asYaml([]config.FileDef{
{
Path: path.Join(dir, "ca.crt"),
Mode: 0644,
Content: string(ca.Cert),
},
{
Path: path.Join(dir, "tls.crt"),
Mode: 0644,
Content: string(kc.Cert),
},
{
Path: path.Join(dir, "tls.key"),
Mode: 0600,
Content: string(kc.Key),
},
})
},
"ssh_host_keys": func(dir, cluster, host string) (s string, err error) {
pairs, err := secretData.SSHKeyPairs(cluster, host)
if err != nil {
return
}
files := make([]config.FileDef, 0, len(pairs)*2)
for _, pair := range pairs {
basePath := path.Join(dir, "ssh_host_"+pair.Type+"_key")
files = append(files, []config.FileDef{
{
Path: basePath,
Mode: 0600,
Content: pair.Private,
},
{
Path: basePath + ".pub",
Mode: 0644,
Content: pair.Public,
},
}...)
}
return asYaml(files)
},
}
func getKeyCert(cluster, caName, name, profile, label, reqJson string) (kc *KeyCert, err error) {
certReq := &csr.CertificateRequest{
KeyRequest: csr.NewBasicKeyRequest(),
}
err = json.Unmarshal([]byte(reqJson), certReq)
if err != nil {
log.Print("CSR unmarshal failed on: ", reqJson)
return
}
return secretData.KeyCert(cluster, caName, name, profile, label, certReq)
}
func asYaml(v interface{}) (string, error) {
ba, err := yaml.Marshal(v)
if err != nil {
return "", err
}
return string(ba), nil
}

View File

@ -4,17 +4,13 @@ import (
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"
"encoding/hex" "encoding/hex"
"encoding/json"
"fmt"
"io" "io"
"log" "log"
"net/http" "net/http"
"path"
"path/filepath" "path/filepath"
"text/template" "text/template"
cfsslconfig "github.com/cloudflare/cfssl/config" cfsslconfig "github.com/cloudflare/cfssl/config"
"github.com/cloudflare/cfssl/csr"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
"novit.nc/direktil/pkg/config" "novit.nc/direktil/pkg/config"
@ -81,7 +77,7 @@ func newRenderContext(host *localconfig.Host, cfg *localconfig.Config) (ctx *ren
func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) { func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
tmpl, err := template.New(ctx.Host.Name + "/config"). tmpl, err := template.New(ctx.Host.Name + "/config").
Funcs(ctx.templateFuncs()). Funcs(templateFuncs).
Parse(ctx.Host.Config) Parse(ctx.Host.Config)
if err != nil { if err != nil {
@ -111,164 +107,6 @@ func (ctx *renderContext) Config() (ba []byte, cfg *config.Config, err error) {
return return
} }
func (ctx *renderContext) templateFuncs() map[string]interface{} {
getKeyCert := func(cluster, caName, name, profile, label, reqJson string) (kc *KeyCert, err error) {
certReq := &csr.CertificateRequest{
KeyRequest: csr.NewBasicKeyRequest(),
}
err = json.Unmarshal([]byte(reqJson), certReq)
if err != nil {
log.Print("CSR unmarshal failed on: ", reqJson)
return
}
return secretData.KeyCert(cluster, caName, name, profile, label, certReq)
}
asYaml := func(v interface{}) (string, error) {
ba, err := yaml.Marshal(v)
if err != nil {
return "", err
}
return string(ba), nil
}
return map[string]interface{}{
"password": func(cluster, name string) (password string, err error) {
password = secretData.Password(cluster, name)
if len(password) == 0 {
err = fmt.Errorf("password %q not defined for cluster %q", name, cluster)
}
return
},
"token": func(cluster, name string) (s string, err error) {
return secretData.Token(cluster, name)
},
"ca_key": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
s = string(ca.Key)
return
},
"ca_crt": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
s = string(ca.Cert)
return
},
"ca_dir": func(cluster, name string) (s string, err error) {
ca, err := secretData.CA(cluster, name)
if err != nil {
return
}
dir := "/etc/tls-ca/" + name
return asYaml([]config.FileDef{
{
Path: path.Join(dir, "ca.crt"),
Mode: 0644,
Content: string(ca.Cert),
},
{
Path: path.Join(dir, "ca.key"),
Mode: 0600,
Content: string(ca.Key),
},
})
},
"tls_key": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
s = string(kc.Key)
return
},
"tls_crt": func(cluster, caName, name, profile, label, reqJson string) (s string, err error) {
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
s = string(kc.Cert)
return
},
"tls_dir": func(dir, cluster, caName, name, profile, label, reqJson string) (s string, err error) {
ca, err := secretData.CA(cluster, caName)
if err != nil {
return
}
kc, err := getKeyCert(cluster, caName, name, profile, label, reqJson)
if err != nil {
return
}
return asYaml([]config.FileDef{
{
Path: path.Join(dir, "ca.crt"),
Mode: 0644,
Content: string(ca.Cert),
},
{
Path: path.Join(dir, "tls.crt"),
Mode: 0644,
Content: string(kc.Cert),
},
{
Path: path.Join(dir, "tls.key"),
Mode: 0600,
Content: string(kc.Key),
},
})
},
"ssh_host_keys": func(dir, cluster, host string) (s string, err error) {
pairs, err := secretData.SSHKeyPairs(cluster, host)
if err != nil {
return
}
files := make([]config.FileDef, 0, len(pairs)*2)
for _, pair := range pairs {
basePath := path.Join(dir, "ssh_host_"+pair.Type+"_key")
files = append(files, []config.FileDef{
{
Path: basePath,
Mode: 0600,
Content: pair.Private,
},
{
Path: basePath + ".pub",
Mode: 0644,
Content: pair.Public,
},
}...)
}
return asYaml(files)
},
}
}
func (ctx *renderContext) distFilePath(path ...string) string { func (ctx *renderContext) distFilePath(path ...string) string {
return filepath.Join(append([]string{*dataDir, "dist"}, path...)...) return filepath.Join(append([]string{*dataDir, "dist"}, path...)...)
} }

View File

@ -59,7 +59,7 @@ func wsClusterAddons(req *restful.Request, resp *restful.Response) {
return return
} }
resp.Write([]byte(cluster.Addons)) wsRender(resp, cluster.Addons, cluster)
} }
func wsClusterPasswords(req *restful.Request, resp *restful.Response) { func wsClusterPasswords(req *restful.Request, resp *restful.Response) {
@ -70,6 +70,7 @@ func wsClusterPasswords(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(secretData.Passwords(cluster.Name)) resp.WriteEntity(secretData.Passwords(cluster.Name))
} }
func wsClusterPassword(req *restful.Request, resp *restful.Response) { func wsClusterPassword(req *restful.Request, resp *restful.Response) {
cluster := wsReadCluster(req, resp) cluster := wsReadCluster(req, resp)
if cluster == nil { if cluster == nil {
@ -80,6 +81,7 @@ func wsClusterPassword(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(secretData.Password(cluster.Name, name)) resp.WriteEntity(secretData.Password(cluster.Name, name))
} }
func wsClusterSetPassword(req *restful.Request, resp *restful.Response) { func wsClusterSetPassword(req *restful.Request, resp *restful.Response) {
cluster := wsReadCluster(req, resp) cluster := wsReadCluster(req, resp)
if cluster == nil { if cluster == nil {
@ -98,6 +100,7 @@ func wsClusterSetPassword(req *restful.Request, resp *restful.Response) {
if err := secretData.Save(); err != nil { if err := secretData.Save(); err != nil {
wsError(resp, err) wsError(resp, err)
return
} }
} }
@ -130,5 +133,5 @@ func wsClusterBootstrapPods(req *restful.Request, resp *restful.Response) {
return return
} }
resp.Write([]byte(cluster.BootstrapPods)) wsRender(resp, cluster.BootstrapPods, cluster)
} }

View File

@ -6,6 +6,7 @@ import (
"net" "net"
"net/http" "net/http"
"strings" "strings"
"text/template"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"novit.nc/direktil/local-server/pkg/mime" "novit.nc/direktil/local-server/pkg/mime"
@ -133,3 +134,17 @@ func wsError(resp *restful.Response, err error) {
http.StatusInternalServerError, http.StatusInternalServerError,
http.StatusText(http.StatusInternalServerError)) http.StatusText(http.StatusInternalServerError))
} }
func wsRender(resp *restful.Response, tmplStr string, value interface{}) {
tmpl, err := template.New("wsRender").Funcs(templateFuncs).Parse(tmplStr)
if err != nil {
wsError(resp, err)
return
}
err = tmpl.Execute(resp, value)
if err != nil {
wsError(resp, err)
return
}
}