From 47aeb05c82b6c193438a6e9cca23703bd78c94d5 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Thu, 15 Sep 2022 16:57:15 +0200 Subject: [PATCH] Rework templating for bootstrap --- cmd/bootstrap.go | 56 ++++-------- .../bootstrap/env => config/config_template} | 0 internal/config/template.go | 91 +++++++++++++++++++ internal/core/core.go | 4 - 4 files changed, 108 insertions(+), 43 deletions(-) rename internal/{core/bootstrap/env => config/config_template} (100%) create mode 100644 internal/config/template.go diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index b62b1b4..330bc45 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -1,7 +1,6 @@ package cmd import ( - "bytes" "io/fs" "os" "path/filepath" @@ -10,10 +9,7 @@ import ( "github.com/FAU-CDI/wisski-distillery/internal/config" "github.com/FAU-CDI/wisski-distillery/internal/core" "github.com/FAU-CDI/wisski-distillery/pkg/fsx" - "github.com/FAU-CDI/wisski-distillery/pkg/hostname" "github.com/FAU-CDI/wisski-distillery/pkg/logging" - "github.com/FAU-CDI/wisski-distillery/pkg/password" - "github.com/FAU-CDI/wisski-distillery/pkg/unpack" "github.com/tkw1536/goprogram/exit" ) @@ -95,12 +91,16 @@ func (bs bootstrap) Run(context wisski_distillery.Context) error { // TODO: Should we read an existing configuration file? wdcliPath := filepath.Join(root, core.Executable) envPath := filepath.Join(root, core.ConfigFile) - domain := bs.Hostname - if domain == "" { - domain = hostname.FQDN() + + // setup a new template for the configuration file! + var tpl config.Template + tpl.DeployRoot = bs.Directory + tpl.DefaultDomain = bs.Hostname + + // and use thge defaults + if err := tpl.SetDefaults(); err != nil { + return errBootstrapWriteConfig.WithMessageF(err) } - overridesPath := filepath.Join(root, core.OverridesJSON) - authorizedKeysFile := filepath.Join(root, core.AuthorizedKeys) { logging.LogMessage(context.IOStream, "Copying over wdcli executable") @@ -119,53 +119,31 @@ func (bs bootstrap) Run(context wisski_distillery.Context) error { { if !fsx.IsFile(envPath) { if err := logging.LogOperation(func() error { - password, err := password.Password(128) - if err != nil { - return errBootstrapWriteConfig.WithMessageF(err) - } - env, err := os.Create(envPath) if err != nil { - return errBootstrapWriteConfig.WithMessageF(err) + return err } - if err := unpack.WriteTemplate( - env, - map[string]string{ - "DEPLOY_ROOT": root, - "DEFAULT_DOMAIN": domain, - "SELF_OVERRIDES_FILE": overridesPath, - "AUTHORIZED_KEYS_FILE": authorizedKeysFile, + defer env.Close() - "GRAPHDB_ADMIN_USER": "admin", - "GRAPHDB_ADMIN_PASSWORD": password[:64], - - "MYSQL_ADMIN_USER": "admin", - "MYSQL_ADMIN_PASSWORD": password[64:], - }, - bytes.NewReader(core.ConfigFileTemplate), - ); err != nil { - return errBootstrapWriteConfig.WithMessageF(err) - } - - return nil + return tpl.MarshalTo(env) }, context.IOStream, "Installing configuration file"); err != nil { - return err + return errBootstrapWriteConfig.WithMessageF(err) } if err := logging.LogOperation(func() error { - context.Println(overridesPath) + context.Println(tpl.SelfOverridesFile) if err := os.WriteFile( - overridesPath, + tpl.SelfOverridesFile, core.DefaultOverridesJSON, fs.ModePerm, ); err != nil { return errBootstrapCreateFile.WithMessageF(err) } - context.Println(authorizedKeysFile) + context.Println(tpl.AuthorizedKeys) if err := os.WriteFile( - authorizedKeysFile, + tpl.AuthorizedKeys, core.DefaultAuthorizedKeys, fs.ModePerm, ); err != nil { diff --git a/internal/core/bootstrap/env b/internal/config/config_template similarity index 100% rename from internal/core/bootstrap/env rename to internal/config/config_template diff --git a/internal/config/template.go b/internal/config/template.go new file mode 100644 index 0000000..f3cee91 --- /dev/null +++ b/internal/config/template.go @@ -0,0 +1,91 @@ +package config + +import ( + "bytes" + "io" + "path/filepath" + "reflect" + + "github.com/FAU-CDI/wisski-distillery/internal/core" + "github.com/FAU-CDI/wisski-distillery/pkg/hostname" + "github.com/FAU-CDI/wisski-distillery/pkg/password" + "github.com/FAU-CDI/wisski-distillery/pkg/unpack" + + _ "embed" +) + +// Template is a template for the cofiguration file +type Template struct { + DeployRoot string `env:"DEPLOY_ROOT"` + DefaultDomain string `env:"DEFAULT_DOMAIN"` + SelfOverridesFile string `env:"SELF_OVERRIDES_FILE"` + AuthorizedKeys string `env:"AUTHORIZED_KEYS_FILE"` + TriplestoreAdminUser string `env:"GRAPHDB_ADMIN_USER"` + TriplestoreAdminPassword string `env:"GRAPHDB_ADMIN_PASSWORD"` + MysqlAdminUsername string `env:"MYSQL_ADMIN_USER"` + MysqlAdminPassword string `env:"MYSQL_ADMIN_PASSWORD"` +} + +// SetDefaults sets defaults on the template +func (tpl *Template) SetDefaults() (err error) { + if tpl.DeployRoot == "" { + tpl.DeployRoot = core.BaseDirectoryDefault + } + + if tpl.DefaultDomain == "" { + tpl.DefaultDomain = hostname.FQDN() + } + + if tpl.SelfOverridesFile == "" { + tpl.SelfOverridesFile = filepath.Join(tpl.DeployRoot, core.OverridesJSON) + } + + if tpl.AuthorizedKeys == "" { + tpl.AuthorizedKeys = filepath.Join(tpl.DeployRoot, core.AuthorizedKeys) + } + + if tpl.TriplestoreAdminUser == "" { + tpl.TriplestoreAdminUser = "admin" + } + + if tpl.TriplestoreAdminPassword == "" { + tpl.TriplestoreAdminPassword, err = password.Password(64) + if err != nil { + return err + } + } + + if tpl.MysqlAdminUsername == "" { + tpl.MysqlAdminUsername = "admin" + } + + if tpl.MysqlAdminPassword == "" { + tpl.MysqlAdminPassword, err = password.Password(64) + if err != nil { + return err + } + } + + return nil +} + +//go:embed config_template +var templateBytes []byte + +// MarshalTo marshals this template into dst +func (tpl Template) MarshalTo(dst io.Writer) error { + tplVal := reflect.ValueOf(tpl) + tplType := reflect.TypeOf(tpl) + + context := make(map[string]string, tplType.NumField()) + for i := 0; i < tplType.NumField(); i++ { + field := tplType.Field(i) + + key := field.Tag.Get("env") + value := tplVal.FieldByName(field.Name).String() + + context[key] = value + } + + return unpack.WriteTemplate(dst, context, bytes.NewReader(templateBytes)) +} diff --git a/internal/core/core.go b/internal/core/core.go index 6b90779..b327353 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -15,10 +15,6 @@ const Executable = "wdcli" // It should be located inside the deployment directory. const ConfigFile = ".env" -// ConfigFileTemplate contains a template for a new configuration file -//go:embed bootstrap/env -var ConfigFileTemplate []byte - // OverridesJSON is the name of the json overrides file. // It should be located inside the deployment directory. const OverridesJSON = "overrides.json"