Move to yaml-based configuration

This commit updates the configuration to be yaml-based and updates the
configuration to read in a yaml file.
This commit is contained in:
Tom Wiesing 2023-02-12 18:13:52 +01:00
parent 568c005d15
commit 945329a080
No known key found for this signature in database
70 changed files with 1150 additions and 350 deletions

View file

@ -55,7 +55,7 @@ func (next *Next) getInstance(r *http.Request) (wisski *wisski.WissKI, path stri
}
// find the slug
slug, ok := next.Config.SlugFromHost(url.Host)
slug, ok := next.Config.HTTP.SlugFromHost(url.Host)
if slug == "" || !ok {
return nil, "", httpx.ErrBadRequest
}

View file

@ -58,7 +58,7 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
return sc, err
}
sc.Domain = panel.Config.DefaultDomain
sc.Domain = panel.Config.HTTP.PrimaryDomain
sc.Port = panel.Config.PublicSSHPort
// pick the first domain that the user has access to as an example
@ -68,7 +68,7 @@ func (panel *UserPanel) sshRoute(ctx context.Context) http.Handler {
} else {
sc.Slug = "example"
}
sc.Hostname = panel.Config.HostFromSlug(sc.Slug)
sc.Hostname = panel.Config.HTTP.HostFromSlug(sc.Slug)
sc.Keys, err = panel.Dependencies.Keys.Keys(r.Context(), user.User.User)
if err != nil {

View file

@ -30,7 +30,7 @@ type Exporter struct {
// Path returns the path that contains all snapshot related data.
func (dis *Exporter) Path() string {
return filepath.Join(dis.Config.DeployRoot, "snapshots")
return filepath.Join(dis.Config.Paths.Root, "snapshots")
}
// StagingPath returns the path to the directory containing a temporary staging area for snapshots.

View file

@ -38,8 +38,8 @@ func (control *Config) Backup(scontext component.StagingContext) error {
func (control *Config) backupFiles() []string {
return []string{
control.Config.ConfigPath,
control.Config.ExecutablePath(),
control.Config.SelfOverridesFile,
control.Config.SelfResolverBlockFile,
control.Config.Paths.ExecutablePath(),
control.Config.Paths.OverridesJSON,
control.Config.Paths.ResolverBlocks,
}
}

View file

@ -12,7 +12,7 @@ import (
// ShouldPrune determines if a file with the provided modification time should be
// removed from the export log.
func (exporter *Exporter) ShouldPrune(modtime time.Time) bool {
return time.Since(modtime) > time.Duration(exporter.Config.MaxBackupAge)*24*time.Hour
return time.Since(modtime) > exporter.Config.MaxBackupAge
}
// Prune prunes all old exports

View file

@ -5,8 +5,8 @@ import (
"path/filepath"
"strings"
"github.com/FAU-CDI/wisski-distillery/internal/config/validators"
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
"github.com/FAU-CDI/wisski-distillery/pkg/stringparser"
)
var (
@ -37,8 +37,8 @@ func (instances *Instances) Create(slug string) (wissKI *wisski.WissKI, err erro
// sql
wissKI.Liquid.Instance.SqlDatabase = instances.Config.MysqlDatabasePrefix + slug
wissKI.Liquid.Instance.SqlUsername = instances.Config.MysqlUserPrefix + slug
wissKI.Liquid.Instance.SqlDatabase = instances.Config.SQL.DataPrefix + slug
wissKI.Liquid.Instance.SqlUsername = instances.Config.SQL.UserPrefix + slug
wissKI.Liquid.Instance.SqlPassword, err = instances.Config.NewPassword()
if err != nil {
@ -47,8 +47,8 @@ func (instances *Instances) Create(slug string) (wissKI *wisski.WissKI, err erro
// triplestore
wissKI.Liquid.Instance.GraphDBRepository = instances.Config.GraphDBRepoPrefix + slug
wissKI.Liquid.Instance.GraphDBUsername = instances.Config.GraphDBUserPrefix + slug
wissKI.Liquid.Instance.GraphDBRepository = instances.Config.TS.DataPrefix + slug
wissKI.Liquid.Instance.GraphDBUsername = instances.Config.TS.UserPrefix + slug
wissKI.Liquid.Instance.GraphDBPassword, err = instances.Config.NewPassword()
if err != nil {
@ -73,7 +73,7 @@ var restrictedSlugs = []string{"www", "admin"}
// IsValidSlug checks if slug represents a valid slug for an instance.
func (instances *Instances) IsValidSlug(slug string) (string, error) {
// check that it is a slug
slug, err := stringparser.ParseSlug(instances.Environment, slug)
err := validators.ValidateSlug(&slug, "")
if err != nil {
return "", errInvalidSlug
}
@ -84,5 +84,5 @@ func (instances *Instances) IsValidSlug(slug string) (string, error) {
}
// return the slug
return strings.ToLower(slug), nil
return slug, nil
}

View file

@ -28,7 +28,7 @@ type Instances struct {
}
func (instances *Instances) Path() string {
return filepath.Join(instances.Still.Config.DeployRoot, "instances")
return filepath.Join(instances.Still.Config.Paths.Root, "instances")
}
// ErrWissKINotFound is returned when a WissKI is not found

View file

@ -22,7 +22,7 @@ var runtimeResources embed.FS
// Update installs or updates runtime components needed by this component.
func (instances *Instances) Update(ctx context.Context, progress io.Writer) error {
err := unpack.InstallDir(instances.Still.Environment, instances.Config.RuntimeDir(), "runtime", runtimeResources, func(dst, src string) {
err := unpack.InstallDir(instances.Still.Environment, instances.Config.Paths.RuntimeDir(), "runtime", runtimeResources, func(dst, src string) {
logging.ProgressF(progress, ctx, "[copy] %s\n", dst)
})
if err != nil {

View file

@ -84,14 +84,14 @@ func (resolver *Resolver) HandleRoute(ctx context.Context, route string) (http.H
}
// handle the default domain name!
domainName := resolver.Config.DefaultDomain
domainName := resolver.Config.HTTP.PrimaryDomain
if domainName != "" {
fallback.Data[fmt.Sprintf("^https?://(.*)\\.%s", regexp.QuoteMeta(domainName))] = fmt.Sprintf("https://$1.%s", domainName)
logger.Info().Str("name", domainName).Msg("registering default domain")
}
// handle the extra domains!
for _, domain := range resolver.Config.SelfExtraDomains {
for _, domain := range resolver.Config.HTTP.ExtraDomains {
fallback.Data[fmt.Sprintf("^https?://(.*)\\.%s", regexp.QuoteMeta(domain))] = fmt.Sprintf("https://$1.%s", domainName)
logger.Info().Str("name", domainName).Msg("registering legacy domain")
}

View file

@ -119,7 +119,7 @@
<code>root</code>
</td>
<td>
<code>{{.Config.DeployRoot}}</code>
<code>{{.Config.Paths.Root}}</code>
</td>
</tr>
<tr>
@ -161,7 +161,7 @@
Docker Network Name
</td>
<td>
<code>{{.Config.DockerNetworkName}}</code>
<code>{{.Config.Docker.Network}}</code>
</td>
</tr>
<tr>

View file

@ -51,7 +51,7 @@ func (home *Home) HandleRoute(ctx context.Context, route string) (http.Handler,
dflt.Fallback = home.publicHandler(ctx)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slug, ok := home.Config.SlugFromHost(r.Host)
slug, ok := home.Config.HTTP.SlugFromHost(r.Host)
switch {
case !ok:
http.NotFound(w, r)

View file

@ -68,7 +68,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
// prepare about
pc.aboutContext.Logo = logoHTML
pc.aboutContext.Instances = home.homeInstances.Get(nil)
pc.aboutContext.SelfRedirect = home.Config.SelfRedirect.String()
pc.aboutContext.SelfRedirect = home.Config.Theme.SelfRedirect.String()
// render the about template

View file

@ -18,7 +18,7 @@ func (home *Home) loadRedirect(ctx context.Context) (redirect Redirect, err erro
redirect.Permanent = false
// load the overrides file
overrides, err := home.Environment.Open(home.Config.SelfOverridesFile)
overrides, err := home.Environment.Open(home.Config.Paths.OverridesJSON)
if err != nil {
return redirect, err
}

View file

@ -39,7 +39,7 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
var publicM, internalM mux.Mux[component.RouteContext]
publicM.Context = func(r *http.Request) component.RouteContext {
slug, ok := server.Still.Config.SlugFromHost(r.Host)
slug, ok := server.Still.Config.HTTP.SlugFromHost(r.Host)
return component.RouteContext{
DefaultDomain: slug == "" && ok,
}
@ -112,7 +112,7 @@ func (server *Server) Server(ctx context.Context, progress io.Writer) (public ht
// CSRF returns a CSRF handler for the given function
func (server *Server) csrf() func(http.Handler) http.Handler {
var opts []csrf.Option
if !server.Config.HTTPSEnabled() {
if !server.Config.HTTP.HTTPSEnabled() {
opts = append(opts, csrf.Secure(false))
}
opts = append(opts, csrf.SameSite(csrf.SameSiteStrictMode))

View file

@ -13,7 +13,7 @@ import (
)
func (control Server) Path() string {
return filepath.Join(control.Still.Config.DeployRoot, "core", "dis")
return filepath.Join(control.Still.Config.Paths.Root, "core", "dis")
}
//go:embed all:server server.env
@ -26,15 +26,15 @@ func (server *Server) Stack(env environment.Environment) component.StackWithReso
EnvPath: "server.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": server.Config.DockerNetworkName,
"HOST_RULE": server.Config.DefaultHostRule(),
"HTTPS_ENABLED": server.Config.HTTPSEnabledEnv(),
"DOCKER_NETWORK_NAME": server.Config.Docker.Network,
"HOST_RULE": server.Config.HTTP.DefaultHostRule(),
"HTTPS_ENABLED": server.Config.HTTP.HTTPSEnabledEnv(),
"CONFIG_PATH": server.Config.ConfigPath,
"DEPLOY_ROOT": server.Config.DeployRoot,
"DEPLOY_ROOT": server.Config.Paths.Root,
"SELF_OVERRIDES_FILE": server.Config.SelfOverridesFile,
"SELF_RESOLVER_BLOCK_FILE": server.Config.SelfResolverBlockFile,
"SELF_OVERRIDES_FILE": server.Config.Paths.OverridesJSON,
"SELF_RESOLVER_BLOCK_FILE": server.Config.Paths.ResolverBlocks,
"CUSTOM_ASSETS_PATH": server.Dependencies.Templating.CustomAssetsPath(),
},
@ -50,6 +50,6 @@ func (server *Server) Trigger(ctx context.Context, env environment.Environment)
func (server *Server) Context(parent component.InstallationContext) component.InstallationContext {
return component.InstallationContext{
bootstrap.Executable: server.Config.CurrentExecutable(server.Environment), // TODO: Does this make sense?
bootstrap.Executable: server.Config.Paths.CurrentExecutable(server.Environment), // TODO: Does this make sense?
}
}

View file

@ -8,7 +8,7 @@ import (
// CustomAssetsPath is the path custom assets are stored at
func (tpl *Templating) CustomAssetsPath() string {
return filepath.Join(tpl.Config.DeployRoot, "core", "assets")
return filepath.Join(tpl.Config.Paths.Root, "core", "assets")
}
func (tpl *Templating) CustomAssetPath(name string) string {

View file

@ -22,7 +22,7 @@ var (
)
func (s *Solr) Path() string {
return filepath.Join(s.Still.Config.DeployRoot, "core", "solr")
return filepath.Join(s.Still.Config.Paths.Root, "core", "solr")
}
func (*Solr) Context(parent component.InstallationContext) component.InstallationContext {
@ -40,7 +40,7 @@ func (solr *Solr) Stack(env environment.Environment) component.StackWithResource
EnvPath: "solr.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": solr.Config.DockerNetworkName,
"DOCKER_NETWORK_NAME": solr.Config.Docker.Network,
},
MakeDirs: []string{

View file

@ -52,7 +52,7 @@ func (sql *SQL) QueryTable(ctx context.Context, table component.Table) (*gorm.DB
// queryTable returns a gorm.DB to connect to the provided distillery database table
func (sql *SQL) queryTable(ctx context.Context, silent bool, table string) (*gorm.DB, error) {
conn, err := sql.connect(sql.Config.DistilleryDatabase)
conn, err := sql.connect(sql.Config.SQL.Database)
if err != nil {
return nil, err
}
@ -117,8 +117,8 @@ func (ssql *SQL) connect(database string) (*sql.DB, error) {
// dsn returns a dsn fof connecting to the database
func (sql *SQL) dsn(database string) string {
user := sql.Config.MysqlAdminUser
pass := sql.Config.MysqlAdminPassword
user := sql.Config.SQL.AdminUsername
pass := sql.Config.SQL.AdminPassword
network := sql.network()
server := sql.ServerURL

View file

@ -31,7 +31,7 @@ var (
)
func (sql *SQL) Path() string {
return filepath.Join(sql.Still.Config.DeployRoot, "core", "sql")
return filepath.Join(sql.Still.Config.Paths.Root, "core", "sql")
}
func (*SQL) Context(parent component.InstallationContext) component.InstallationContext {
@ -49,8 +49,8 @@ func (sql *SQL) Stack(env environment.Environment) component.StackWithResources
EnvPath: "sql.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": sql.Config.DockerNetworkName,
"HTTPS_ENABLED": sql.Config.HTTPSEnabledEnv(),
"DOCKER_NETWORK_NAME": sql.Config.Docker.Network,
"HTTPS_ENABLED": sql.Config.HTTP.HTTPSEnabledEnv(),
},
MakeDirsPerm: environment.DefaultDirPerm,

View file

@ -54,8 +54,8 @@ func (sql *SQL) Update(ctx context.Context, progress io.Writer) error {
}
logging.LogMessage(progress, ctx, "Creating administrative user")
{
username := sql.Config.MysqlAdminUser
password := sql.Config.MysqlAdminPassword
username := sql.Config.SQL.AdminUsername
password := sql.Config.SQL.AdminPassword
if err := sql.CreateSuperuser(ctx, username, password, true); err != nil {
return errSQLUnableToCreateUser
}
@ -65,10 +65,10 @@ func (sql *SQL) Update(ctx context.Context, progress io.Writer) error {
// create the admin user
logging.LogMessage(progress, ctx, "Creating sql database")
{
if !sqle.IsSafeDatabaseLiteral(sql.Config.DistilleryDatabase) {
if !sqle.IsSafeDatabaseLiteral(sql.Config.SQL.Database) {
return errSQLUnsafeDatabaseName
}
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", sql.Config.DistilleryDatabase)
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", sql.Config.SQL.Database)
if err := sql.Exec(createDBSQL); err != nil {
return err
}

View file

@ -26,7 +26,7 @@ func (ssh2 *SSH2) HandleRoute(ctx context.Context, path string) (http.Handler, e
}
// find the host
slug, ok := ssh2.Config.SlugFromHost(r.Host)
slug, ok := ssh2.Config.HTTP.SlugFromHost(r.Host)
if slug == "" || !ok {
httpx.TextInterceptor.Intercept(w, r, httpx.ErrNotFound)
return

View file

@ -36,14 +36,15 @@ func (ssh2 *SSH2) handleDirectTCP(srv *ssh.Server, conn *gossh.ServerConn, newCh
return
}
slug, ok := ssh2.Config.SlugFromHost(d.DestAddr)
slug, ok := ssh2.Config.HTTP.SlugFromHost(d.DestAddr)
if !ok || d.DestPort != 22 || !hasPermission(ctx, slug) {
newChan.Reject(gossh.Prohibited, "permission denied")
return
}
// TODO: move this into an instance function somewhere
dest := net.JoinHostPort(slug+"."+ssh2.Config.DefaultDomain+".wisski", "22")
// NOTE(twiesing): This should be moved
dest := net.JoinHostPort(slug+"."+ssh2.Config.HTTP.PrimaryDomain+".wisski", "22")
var dialer net.Dialer
dconn, err := dialer.DialContext(ctx, "tcp", dest)

View file

@ -80,8 +80,8 @@ func (ssh2 *SSH2) handleConnection(session ssh.Session) {
banner := welcomeMessage
for _, oldnew := range [][2]string{
{"${SLUG}", slug},
{"${DOMAIN}", ssh2.Config.DefaultDomain},
{"${HOSTNAME}", slug + "." + ssh2.Config.DefaultDomain},
{"${DOMAIN}", ssh2.Config.HTTP.PrimaryDomain},
{"${HOSTNAME}", slug + "." + ssh2.Config.HTTP.PrimaryDomain},
{"${PORT}", strconv.FormatUint(uint64(ssh2.Config.PublicSSHPort), 10)},
} {
banner = strings.ReplaceAll(banner, oldnew[0], oldnew[1])

View file

@ -11,7 +11,7 @@ import (
)
func (ssh SSH2) Path() string {
return filepath.Join(ssh.Still.Config.DeployRoot, "core", "ssh2")
return filepath.Join(ssh.Still.Config.Paths.Root, "core", "ssh2")
}
//go:embed all:ssh2 ssh2.env
@ -24,15 +24,15 @@ func (ssh *SSH2) Stack(env environment.Environment) component.StackWithResources
EnvPath: "ssh2.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": ssh.Config.DockerNetworkName,
"HOST_RULE": ssh.Config.DefaultHostRule(),
"HTTPS_ENABLED": ssh.Config.HTTPSEnabledEnv(),
"DOCKER_NETWORK_NAME": ssh.Config.Docker.Network,
"HOST_RULE": ssh.Config.HTTP.DefaultHostRule(),
"HTTPS_ENABLED": ssh.Config.HTTP.HTTPSEnabledEnv(),
"CONFIG_PATH": ssh.Config.ConfigPath,
"DEPLOY_ROOT": ssh.Config.DeployRoot,
"DEPLOY_ROOT": ssh.Config.Paths.Root,
"SELF_OVERRIDES_FILE": ssh.Config.SelfOverridesFile,
"SELF_RESOLVER_BLOCK_FILE": ssh.Config.SelfResolverBlockFile,
"SELF_OVERRIDES_FILE": ssh.Config.Paths.OverridesJSON,
"SELF_RESOLVER_BLOCK_FILE": ssh.Config.Paths.ResolverBlocks,
"SSH_PORT": strconv.FormatUint(uint64(ssh.Config.PublicSSHPort), 10),
},
@ -44,6 +44,6 @@ func (ssh *SSH2) Stack(env environment.Environment) component.StackWithResources
func (ssh SSH2) Context(parent component.InstallationContext) component.InstallationContext {
return component.InstallationContext{
bootstrap.Executable: ssh.Config.CurrentExecutable(ssh.Environment), // TODO: Does this make sense?
bootstrap.Executable: ssh.Config.Paths.CurrentExecutable(ssh.Environment), // TODO: Does this make sense?
}
}

View file

@ -86,7 +86,7 @@ func (ts Triplestore) OpenRaw(ctx context.Context, method, url string, body any,
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
req.SetBasicAuth(ts.Config.TriplestoreAdminUser, ts.Config.TriplestoreAdminPassword)
req.SetBasicAuth(ts.Config.TS.AdminUsername, ts.Config.TS.AdminPassword)
// and send it
return client.Do(req)

View file

@ -25,7 +25,7 @@ var (
)
func (ts *Triplestore) Path() string {
return filepath.Join(ts.Still.Config.DeployRoot, "core", "triplestore")
return filepath.Join(ts.Still.Config.Paths.Root, "core", "triplestore")
}
func (Triplestore) Context(parent component.InstallationContext) component.InstallationContext {
@ -45,7 +45,7 @@ func (ts *Triplestore) Stack(env environment.Environment) component.StackWithRes
EnvPath: "triplestore.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": ts.Config.DockerNetworkName,
"DOCKER_NETWORK_NAME": ts.Config.Docker.Network,
},
MakeDirs: []string{

View file

@ -20,8 +20,8 @@ func (ts Triplestore) Update(ctx context.Context, progress io.Writer) error {
logging.LogMessage(progress, ctx, "Resetting admin user password")
{
res, err := ts.OpenRaw(ctx, "PUT", "/rest/security/users/"+ts.Config.TriplestoreAdminUser, TriplestoreUserPayload{
Password: ts.Config.TriplestoreAdminPassword,
res, err := ts.OpenRaw(ctx, "PUT", "/rest/security/users/"+ts.Config.TS.AdminUsername, TriplestoreUserPayload{
Password: ts.Config.TS.AdminPassword,
AppSettings: TriplestoreUserAppSettings{
DefaultInference: true,
DefaultVisGraphSchema: true,

View file

@ -20,7 +20,7 @@ var (
)
func (web *Web) Path() string {
return filepath.Join(web.Still.Config.DeployRoot, "core", "web")
return filepath.Join(web.Still.Config.Paths.Root, "core", "web")
}
func (*Web) Context(parent component.InstallationContext) component.InstallationContext {
@ -28,7 +28,7 @@ func (*Web) Context(parent component.InstallationContext) component.Installation
}
func (web Web) Stack(env environment.Environment) component.StackWithResources {
if web.Config.HTTPSEnabled() {
if web.Config.HTTP.HTTPSEnabled() {
return web.stackHTTPS(env)
} else {
return web.stackHTTP(env)
@ -46,8 +46,8 @@ func (web *Web) stackHTTPS(env environment.Environment) component.StackWithResou
EnvPath: "web.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": web.Config.DockerNetworkName,
"CERT_EMAIL": web.Config.CertbotEmail,
"DOCKER_NETWORK_NAME": web.Config.Docker.Network,
"CERT_EMAIL": web.Config.HTTP.CertbotEmail,
},
TouchFilesPerm: 0600,
TouchFiles: []string{"acme.json"},
@ -65,8 +65,8 @@ func (web *Web) stackHTTP(env environment.Environment) component.StackWithResour
EnvPath: "web.env",
EnvContext: map[string]string{
"DOCKER_NETWORK_NAME": web.Config.DockerNetworkName,
"CERT_EMAIL": web.Config.CertbotEmail,
"DOCKER_NETWORK_NAME": web.Config.Docker.Network,
"CERT_EMAIL": web.Config.HTTP.CertbotEmail,
},
})
}