fix: render template for addons and bootstrap pods
This commit is contained in:
parent
49a16fe550
commit
1ee5d1c15a
168
cmd/dkl-local-server/cluster-render-context.go
Normal file
168
cmd/dkl-local-server/cluster-render-context.go
Normal 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
|
||||||
|
}
|
@ -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...)...)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user