Start of DB initialisation functions
Not properly working yet
This commit is contained in:
parent
df5e990693
commit
6bd1a86337
@ -22,6 +22,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"flag"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
@ -43,11 +44,29 @@ import (
|
|||||||
"gitlab.com/blender/flamenco-ng-poc/pkg/api"
|
"gitlab.com/blender/flamenco-ng-poc/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var cliArgs struct {
|
||||||
|
version bool
|
||||||
|
initDB bool
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
output := zerolog.ConsoleWriter{Out: colorable.NewColorableStdout(), TimeFormat: time.RFC3339}
|
output := zerolog.ConsoleWriter{Out: colorable.NewColorableStdout(), TimeFormat: time.RFC3339}
|
||||||
log.Logger = log.Output(output)
|
log.Logger = log.Output(output)
|
||||||
log.Info().Str("version", appinfo.ApplicationVersion).Msgf("starting %v", appinfo.ApplicationName)
|
log.Info().Str("version", appinfo.ApplicationVersion).Msgf("starting %v", appinfo.ApplicationName)
|
||||||
|
|
||||||
|
parseCliArgs()
|
||||||
|
if cliArgs.version {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cliArgs.initDB {
|
||||||
|
log.Info().Msg("creating databases")
|
||||||
|
err := persistence.InitialSetup()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("problem performing initial setup")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Open the database.
|
// Open the database.
|
||||||
dbCtx, dbCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
dbCtx, dbCtxCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
defer dbCtxCancel()
|
defer dbCtxCancel()
|
||||||
@ -113,3 +132,27 @@ func buildWebService(flamenco api.ServerInterface, persist api_impl.PersistenceS
|
|||||||
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseCliArgs() {
|
||||||
|
var quiet, debug, trace bool
|
||||||
|
|
||||||
|
flag.BoolVar(&cliArgs.version, "version", false, "Shows the application version, then exits.")
|
||||||
|
flag.BoolVar(&cliArgs.initDB, "initdb", false, "Create the database; requires admin access to PostgreSQL.")
|
||||||
|
flag.BoolVar(&quiet, "quiet", false, "Only log warning-level and worse.")
|
||||||
|
flag.BoolVar(&debug, "debug", false, "Enable debug-level logging.")
|
||||||
|
flag.BoolVar(&trace, "trace", false, "Enable trace-level logging.")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var logLevel zerolog.Level
|
||||||
|
switch {
|
||||||
|
case trace:
|
||||||
|
logLevel = zerolog.TraceLevel
|
||||||
|
case debug:
|
||||||
|
logLevel = zerolog.DebugLevel
|
||||||
|
case quiet:
|
||||||
|
logLevel = zerolog.WarnLevel
|
||||||
|
default:
|
||||||
|
logLevel = zerolog.InfoLevel
|
||||||
|
}
|
||||||
|
zerolog.SetGlobalLevel(logLevel)
|
||||||
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -54,6 +54,7 @@ require (
|
|||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
golang.org/x/mod v0.4.2 // indirect
|
golang.org/x/mod v0.4.2 // indirect
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||||
golang.org/x/tools v0.1.7 // indirect
|
golang.org/x/tools v0.1.7 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -306,6 +306,8 @@ golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1U
|
|||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
141
internal/manager/persistence/initialisation.go
Normal file
141
internal/manager/persistence/initialisation.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package persistence
|
||||||
|
|
||||||
|
/* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* Original Code Copyright (C) 2022 Blender Foundation.
|
||||||
|
*
|
||||||
|
* This file is part of Flamenco.
|
||||||
|
*
|
||||||
|
* Flamenco is free software: you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* Flamenco is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* Flamenco. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"golang.org/x/term"
|
||||||
|
"gorm.io/driver/postgres"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errInputTooLong = errors.New("input is too long")
|
||||||
|
|
||||||
|
const adminDSN = "host=localhost user=postgres password=%s dbname=%s TimeZone=Europe/Amsterdam"
|
||||||
|
|
||||||
|
// InitialSetup uses the `postgres` admin user to set up the database.
|
||||||
|
// TODO: distinguish between production and development setups.
|
||||||
|
func InitialSetup() error {
|
||||||
|
// Get the password of the 'postgres' user.
|
||||||
|
adminPass, err := readPassword()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to read password: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect to the 'postgres' database so we can create other databases.
|
||||||
|
db, err := connectDBAsAdmin(adminPass, "postgres")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to connect to the database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: get username / password / database name from some config file, user input, CLI args, whatevah.
|
||||||
|
// Has to be used by the regular Flamenco Manager runs as well, though.
|
||||||
|
username := "flamenco"
|
||||||
|
userPass := "flamenco"
|
||||||
|
// tx := db.Exec("CREATE USER flamenco PASSWORD ? NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN", userPass)
|
||||||
|
// if tx.Error != nil {
|
||||||
|
// return fmt.Errorf("unable to create database user '%s': %w", username, tx.Error)
|
||||||
|
// }
|
||||||
|
{
|
||||||
|
sqlDB, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = sqlDB.Exec("CREATE USER flamenco WITH PASSWORD $1::string NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN", userPass)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the databases.
|
||||||
|
tx := db.Debug().Exec("CREATE DATABASE flamenco OWNER ? ENCODING 'utf8'", username)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return fmt.Errorf("unable to create database 'flamenco': %w", tx.Error)
|
||||||
|
}
|
||||||
|
tx = db.Exec("CREATE DATABASE flamenco-test OWNER ? ENCODING 'utf8'", username)
|
||||||
|
if tx.Error != nil {
|
||||||
|
return fmt.Errorf("unable to create database 'flamenco': %w", tx.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the connection so we can reconnect.
|
||||||
|
sqlDB, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("error closing the database connection, please report this issue: %v", err)
|
||||||
|
} else {
|
||||||
|
sqlDB.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow 'flamenco' user to completely nuke and recreate the flamenco-test database, without needing 'CREATEDB' permission.
|
||||||
|
db, err = connectDBAsAdmin(adminPass, "flamenco-test")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to reconnect to the database: %w", err)
|
||||||
|
}
|
||||||
|
tx = db.Exec("ALTER SCHEMA public OWNER TO ?", username)
|
||||||
|
if tx.Error != nil {
|
||||||
|
fmt.Printf("Unable to allow database user '%s' to reset the test database: %v\n", username, tx.Error)
|
||||||
|
fmt.Println("This is not an issue, unless you want to develop Flamenco yourself.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readPassword() (string, error) {
|
||||||
|
if pwFromEnv := os.Getenv("PSQL_ADMIN"); pwFromEnv != "" {
|
||||||
|
log.Info().Msg("getting password from PSQL_ADMIN environment variable")
|
||||||
|
return pwFromEnv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("PostgreSQL admin password: ")
|
||||||
|
|
||||||
|
var (
|
||||||
|
line []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
// term.ReadPassword() doesn't work reliably on Windows, especially when you
|
||||||
|
// use a MingW terminal (like Git Bash). See
|
||||||
|
// https://github.com/golang/go/issues/11914#issuecomment-613715787 for more
|
||||||
|
// info.
|
||||||
|
//
|
||||||
|
// The downside is that this echoes the password to the terminal.
|
||||||
|
buf := bufio.NewReader(os.Stdin)
|
||||||
|
line, _, err = buf.ReadLine()
|
||||||
|
} else {
|
||||||
|
fd := int(os.Stdin.Fd())
|
||||||
|
line, err = term.ReadPassword(fd)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(line), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectDBAsAdmin(password, database string) (*gorm.DB, error) {
|
||||||
|
dsn := fmt.Sprintf(adminDSN, password, database)
|
||||||
|
return gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user