env: Move each component into a separate struct

This commit cleans up the distillery code by making each component a
distinct struct. Each of these components is also returned by by a new
Component() function that replaces the Stacks() function.
This commit is contained in:
Tom Wiesing 2022-09-05 15:50:23 +02:00
parent 2a14d93d3c
commit 09431c4869
No known key found for this signature in database
16 changed files with 265 additions and 148 deletions

19
env/instances.go vendored
View file

@ -37,11 +37,12 @@ var errSQL = exit.Error{
// Instance returns the instance of the WissKI Distillery with the provided slug
func (dis *Distillery) Instance(slug string) (i Instance, err error) {
if err := dis.SQLWaitForConnection(); err != nil {
sql := dis.SQL()
if err := sql.Wait(); err != nil {
return i, err
}
table, err := dis.sqlBkTable(false)
table, err := sql.OpenBookkeeping(false)
if err != nil {
return i, err
}
@ -61,11 +62,12 @@ func (dis *Distillery) Instance(slug string) (i Instance, err error) {
// HasInstance checks if the provided instance exists in the bookeeping table
func (dis *Distillery) HasInstance(slug string) (ok bool, err error) {
if err := dis.SQLWaitForConnection(); err != nil {
sql := dis.SQL()
if err := sql.Wait(); err != nil {
return false, err
}
table, err := dis.sqlBkTable(false)
table, err := sql.OpenBookkeeping(false)
if err != nil {
return false, err
}
@ -104,12 +106,13 @@ func (dis *Distillery) InstancesWith(slugs ...string) ([]Instance, error) {
// findInstances finds instance objects based on a query in the bookkeeping table
func (dis *Distillery) findInstances(order bool, query func(table *gorm.DB) *gorm.DB) (instances []Instance, err error) {
if err := dis.SQLWaitForConnection(); err != nil {
sql := dis.SQL()
if err := sql.Wait(); err != nil {
return nil, err
}
// open the bookkeeping table
table, err := dis.sqlBkTable(false)
table, err := sql.OpenBookkeeping(false)
if err != nil {
return nil, err
}
@ -153,7 +156,7 @@ type Instance struct {
// Update updates the bookkeeping table with this instance.
func (instance *Instance) Update() error {
db, err := instance.dis.sqlBkTable(false)
db, err := instance.dis.SQL().OpenBookkeeping(false)
if err != nil {
return err
}
@ -169,7 +172,7 @@ func (instance *Instance) Update() error {
// Delete deletes this instance from the bookkeeping table
func (instance *Instance) Delete() error {
db, err := instance.dis.sqlBkTable(false)
db, err := instance.dis.SQL().OpenBookkeeping(false)
if err != nil {
return err
}

29
env/stack.go vendored
View file

@ -9,20 +9,31 @@ import (
// TODO: Move everything into specific subpackages
// Stacks returns the Stacks of this distillery
func (dis *Distillery) Stacks() []stack.Installable {
func (dis *Distillery) Components() []Component {
// TODO: Do we want to cache these stacks?
return []stack.Installable{
dis.WebStack(),
dis.SelfStack(),
dis.ResolverStack(),
dis.SSHStack(),
dis.TriplestoreStack(),
dis.SQLStack(),
return []Component{
dis.Web(),
dis.Self(),
dis.Resolver(),
dis.SSH(),
dis.Triplestore(),
dis.SQL(),
}
}
// Component represents a component of the distillery
type Component interface {
Name() string // Name is the name of this component
Stack() stack.Installable // Stack returns the installable stack representing this component
Path() string // Path returns the path to this component
}
// asCoreStack treats the provided stack as a core component of this distillery.
func (dis *Distillery) asCoreStack(name string, stack stack.Installable) stack.Installable {
func (dis *Distillery) makeComponentStack(component Component, stack stack.Installable) stack.Installable {
name := component.Name()
stack.Dir = filepath.Join(dis.Config.DeployRoot, "core", name)
stack.ContextResource = filepath.Join("resources", "compose", name)

46
env/stack_resolver.go vendored
View file

@ -7,29 +7,47 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/stack"
)
const ResolverPrefixFile = "prefix.cfg"
// ResolverComponent represents the 'resolver' layer belonging to a distillery
type ResolverComponent struct {
ConfigName string // Filename of the configuration file
func (dis *Distillery) ResolverStack() stack.Installable {
stack := dis.asCoreStack("resolver", stack.Installable{
dis *Distillery
}
// Resolver returns the ResolverComponent belonging to this distillery
func (dis *Distillery) Resolver() ResolverComponent {
return ResolverComponent{
ConfigName: "prefix.cfg",
dis: dis,
}
}
func (ResolverComponent) Name() string {
return "resolver"
}
func (resolver ResolverComponent) Stack() stack.Installable {
stack := resolver.dis.makeComponentStack(resolver, stack.Installable{
EnvFileContext: map[string]string{
"VIRTUAL_HOST": dis.DefaultVirtualHost(),
"LETSENCRYPT_HOST": dis.DefaultLetsencryptHost(),
"LETSENCRYPT_EMAIL": dis.Config.CertbotEmail,
"VIRTUAL_HOST": resolver.dis.DefaultVirtualHost(),
"LETSENCRYPT_HOST": resolver.dis.DefaultLetsencryptHost(),
"LETSENCRYPT_EMAIL": resolver.dis.Config.CertbotEmail,
"PREFIX_FILE": "", // set below!
"DEFAULT_DOMAIN": dis.Config.DefaultDomain,
"LEGACY_DOMAIN": strings.Join(dis.Config.SelfExtraDomains, ","),
"DEFAULT_DOMAIN": resolver.dis.Config.DefaultDomain,
"LEGACY_DOMAIN": strings.Join(resolver.dis.Config.SelfExtraDomains, ","),
},
TouchFiles: []string{ResolverPrefixFile},
TouchFiles: []string{resolver.ConfigName},
})
stack.EnvFileContext["PREFIX_FILE"] = filepath.Join(stack.Dir, ResolverPrefixFile)
stack.EnvFileContext["PREFIX_FILE"] = filepath.Join(stack.Dir, resolver.ConfigName)
return stack
}
func (dis *Distillery) ResolverStackPath() string {
return dis.ResolverStack().Dir
func (resolver ResolverComponent) Path() string {
return resolver.Stack().Dir
}
func (dis Distillery) ResolverPrefixConfig() string {
return filepath.Join(dis.ResolverStackPath(), ResolverPrefixFile)
func (resolver ResolverComponent) ConfigPath() string {
return filepath.Join(resolver.Path(), resolver.ConfigName)
}

34
env/stack_self.go vendored
View file

@ -2,23 +2,37 @@ package env
import "github.com/FAU-CDI/wisski-distillery/internal/stack"
func (dis *Distillery) SelfStack() stack.Installable {
// SelfComponent represents the 'self' layer belonging to a distillery
type SelfComponent struct {
dis *Distillery
}
// Self returns the SelfComponent belonging to this distillery
func (dis *Distillery) Self() SelfComponent {
return SelfComponent{dis: dis}
}
func (SelfComponent) Name() string {
return "self"
}
func (sc SelfComponent) Stack() stack.Installable {
TARGET := "https://github.com/FAU-CDI/wisski-distillery"
if dis.Config.SelfRedirect != nil {
TARGET = dis.Config.SelfRedirect.String()
if sc.dis.Config.SelfRedirect != nil {
TARGET = sc.dis.Config.SelfRedirect.String()
}
return dis.asCoreStack("self", stack.Installable{
return sc.dis.makeComponentStack(sc, stack.Installable{
EnvFileContext: map[string]string{
"VIRTUAL_HOST": dis.DefaultVirtualHost(),
"LETSENCRYPT_HOST": dis.DefaultLetsencryptHost(),
"LETSENCRYPT_EMAIL": dis.Config.CertbotEmail,
"VIRTUAL_HOST": sc.dis.DefaultVirtualHost(),
"LETSENCRYPT_HOST": sc.dis.DefaultLetsencryptHost(),
"LETSENCRYPT_EMAIL": sc.dis.Config.CertbotEmail,
"TARGET": TARGET,
"OVERRIDES_FILE": dis.Config.SelfOverridesFile,
"OVERRIDES_FILE": sc.dis.Config.SelfOverridesFile,
},
})
}
func (dis *Distillery) SelfStackPath() string {
return dis.SelfStack().Dir
func (sc SelfComponent) Path() string {
return sc.Stack().Dir
}

118
env/stack_sql.go vendored
View file

@ -18,9 +18,29 @@ import (
"gorm.io/gorm/logger"
)
// SQLStack returns the docker stack that handles the sql database.
func (dis *Distillery) SQLStack() stack.Installable {
return dis.asCoreStack("sql", stack.Installable{
// SQLComponent represents the 'sql' layer belonging to a distillery
type SQLComponent struct {
PollInterval time.Duration // Duration to wait for during wait
dis *Distillery
}
// SSH returns the SSHComponent belonging to this distillery
func (dis *Distillery) SQL() SQLComponent {
return SQLComponent{
PollInterval: time.Second,
dis: dis,
}
}
func (SQLComponent) Name() string {
return "sql"
}
// Stack returns the docker stack that handles the sql database.
func (sql SQLComponent) Stack() stack.Installable {
return sql.dis.makeComponentStack(sql, stack.Installable{
MakeDirsPerm: fs.ModeDir | fs.ModePerm,
MakeDirs: []string{
"data",
@ -29,18 +49,18 @@ func (dis *Distillery) SQLStack() stack.Installable {
}
// SQLStackPath returns the path the SQLStack() lives at.
func (dis *Distillery) SQLStackPath() string {
return dis.SQLStack().Dir
func (sql SQLComponent) Path() string {
return sql.Stack().Dir
}
// sqlOpen opens a new sql connection to the provided database using the administrative credentials
func (env Distillery) sqlOpen(database string, config *gorm.Config) (*gorm.DB, error) {
sql := mysql.Config{
DSN: fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", env.Config.MysqlAdminUser, env.Config.MysqlAdminPassword, "127.0.0.1:3306", database),
func (sql SQLComponent) openDatabase(database string, config *gorm.Config) (*gorm.DB, error) {
cfg := mysql.Config{
DSN: fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", sql.dis.Config.MysqlAdminUser, sql.dis.Config.MysqlAdminPassword, "127.0.0.1:3306", database),
DefaultStringSize: 256,
}
db, err := gorm.Open(mysql.New(sql), config)
db, err := gorm.Open(mysql.New(cfg), config)
if err != nil {
return db, err
}
@ -54,8 +74,8 @@ func (env Distillery) sqlOpen(database string, config *gorm.Config) (*gorm.DB, e
return db, nil
}
// sqlBkTable returns a gorm connection to the bookkeeping database.
func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
// OpenBookkeeping opens a connection to the bookkeeping database
func (sql SQLComponent) OpenBookkeeping(silent bool) (*gorm.DB, error) {
config := &gorm.Config{}
if silent {
@ -63,13 +83,13 @@ func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
}
// open the database
db, err := dis.sqlOpen(dis.Config.DistilleryBookkeepingDatabase, config)
db, err := sql.openDatabase(sql.dis.Config.DistilleryBookkeepingDatabase, config)
if err != nil {
return nil, err
}
// load the table
table := db.Table(dis.Config.DistilleryBookkeepingTable)
table := db.Table(sql.dis.Config.DistilleryBookkeepingTable)
if table.Error != nil {
return nil, err
}
@ -79,11 +99,11 @@ func (dis *Distillery) sqlBkTable(silent bool) (*gorm.DB, error) {
var errSQLBackup = errors.New("SQLBackup: Mysqldump returned non-zero exit code")
// SQLBackup makes a backup of the sql database into dest.
func (dis *Distillery) SQLBackup(io stream.IOStream, dest io.Writer, database string) error {
// Backup makes a backup of the sql database into dest.
func (sql SQLComponent) Backup(io stream.IOStream, dest io.Writer, database string) error {
io = stream.NewIOStream(dest, io.Stderr, nil, 0)
code, err := dis.SQLStack().Exec(io, "sql", "mysqldump", "--database", database)
code, err := sql.Stack().Exec(io, "sql", "mysqldump", "--database", database)
if err != nil {
return err
}
@ -93,42 +113,40 @@ func (dis *Distillery) SQLBackup(io stream.IOStream, dest io.Writer, database st
return nil
}
// SQLShell executes a mysql shell inside the SQLStack.
func (dis *Distillery) SQLShell(io stream.IOStream, argv ...string) (int, error) {
return dis.SQLStack().Exec(io, "sql", "mysql", argv...)
// OpenShell executes a mysql shell command
func (sql SQLComponent) OpenShell(io stream.IOStream, argv ...string) (int, error) {
return sql.Stack().Exec(io, "sql", "mysql", argv...)
}
const waitSQLInterval = 1 * time.Second
// SQLWaitForShell waits for the sql database to be reachable via a docker-compose shell
func (dis *Distillery) SQLWaitForShell() error {
// WaitShell waits for the sql database to be reachable via a docker-compose shell
func (sql SQLComponent) WaitShell() error {
n := stream.FromNil()
return wait.Wait(func() bool {
code, err := dis.SQLShell(n, "-e", "show databases;")
code, err := sql.OpenShell(n, "-e", "show databases;")
return err == nil && code == 0
}, waitSQLInterval, dis.Context())
}, sql.PollInterval, sql.dis.Context())
}
// SQLWaitForConnection waits for the sql connection to be alive
func (dis *Distillery) SQLWaitForConnection() error {
// Wait waits for a connection to the bookkeeping table to suceed
func (sql SQLComponent) Wait() error {
return wait.Wait(func() bool {
_, err := dis.sqlBkTable(true)
_, err := sql.OpenBookkeeping(true)
return err == nil
}, waitSQLInterval, dis.Context())
}, sql.PollInterval, sql.dis.Context())
}
var errInvalidDatabaseName = errors.New("SQLProvision: Invalid database name")
func (dis *Distillery) sqlRaw(query string, args ...interface{}) bool {
sql := sqle.Format(query, args...)
code, err := dis.SQLShell(stream.FromNil(), "-e", sql)
func (sql SQLComponent) Query(query string, args ...interface{}) bool {
raw := sqle.Format(query, args...)
code, err := sql.OpenShell(stream.FromNil(), "-e", raw)
return err == nil && code == 0
}
// SQLProvision provisions a new sql database and user
func (dis *Distillery) SQLProvision(name, user, password string) error {
func (sql SQLComponent) Provision(name, user, password string) error {
// wait for the database
if err := dis.SQLWaitForShell(); err != nil {
if err := sql.WaitShell(); err != nil {
return err
}
@ -138,7 +156,7 @@ func (dis *Distillery) SQLProvision(name, user, password string) error {
}
// create the database and user!
if !dis.sqlRaw("CREATE DATABASE `"+name+"`; CREATE USER ?@`%` IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON `"+name+"`.* TO ?@`%`; FLUSH PRIVILEGES;", user, password, user) {
if !sql.Query("CREATE DATABASE `"+name+"`; CREATE USER ?@`%` IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON `"+name+"`.* TO ?@`%`; FLUSH PRIVILEGES;", user, password, user) {
return errors.New("SQLProvision: Failed to create user")
}
@ -149,8 +167,8 @@ func (dis *Distillery) SQLProvision(name, user, password string) error {
var errSQLPurgeUser = errors.New("unable to delete user")
// SQLPurgeUser deletes the specified user from the database
func (dis *Distillery) SQLPurgeUser(user string) error {
if !dis.sqlRaw("DROP USER IF EXISTS ?@`%`; FLUSH PRIVILEGES; ", user) {
func (sql SQLComponent) PurgeUser(user string) error {
if !sql.Query("DROP USER IF EXISTS ?@`%`; FLUSH PRIVILEGES; ", user) {
return errSQLPurgeUser
}
@ -160,11 +178,11 @@ func (dis *Distillery) SQLPurgeUser(user string) error {
var errSQLPurgeDB = errors.New("unable to drop database")
// SQLPurgeDatabase deletes the specified db from the database
func (dis *Distillery) SQLPurgeDatabase(db string) error {
func (sql SQLComponent) PurgeDatabase(db string) error {
if !sqle.IsSafeDatabaseName(db) {
return errSQLPurgeDB
}
if !dis.sqlRaw("DROP DATABASE IF EXISTS `" + db + "`") {
if !sql.Query("DROP DATABASE IF EXISTS `" + db + "`") {
return errSQLPurgeDB
}
return nil
@ -174,18 +192,18 @@ var errSQLUnableToCreateUser = errors.New("unable to create administrative user"
var errSQLUnsafeDatabaseName = errors.New("Bookkeeping database has an unsafe name")
var errSQLUnableToCreate = errors.New("unable to create bookkeeping database")
// SQLBootstrap bootstraps the SQL database, and makes sure that the bookkeeping table is up-to-date
func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
if err := dis.SQLWaitForShell(); err != nil {
// Bootstrap bootstraps the SQL database, and makes sure that the bookkeeping table is up-to-date
func (sql SQLComponent) Bootstrap(io stream.IOStream) error {
if err := sql.WaitShell(); err != nil {
return err
}
// create the admin user
logging.LogMessage(io, "Creating administrative user")
{
username := dis.Config.MysqlAdminUser
password := dis.Config.MysqlAdminPassword
if !dis.sqlRaw("CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON *.* TO ?@`%` WITH GRANT OPTION; FLUSH PRIVILEGES;", username, password, username) {
username := sql.dis.Config.MysqlAdminUser
password := sql.dis.Config.MysqlAdminPassword
if !sql.Query("CREATE USER IF NOT EXISTS ?@'%' IDENTIFIED BY ?; GRANT ALL PRIVILEGES ON *.* TO ?@`%` WITH GRANT OPTION; FLUSH PRIVILEGES;", username, password, username) {
return errSQLUnableToCreateUser
}
}
@ -193,23 +211,23 @@ func (dis *Distillery) SQLBootstrap(io stream.IOStream) error {
// create the admin user
logging.LogMessage(io, "Creating sql database")
{
if !sqle.IsSafeDatabaseName(dis.Config.DistilleryBookkeepingDatabase) {
if !sqle.IsSafeDatabaseName(sql.dis.Config.DistilleryBookkeepingDatabase) {
return errSQLUnsafeDatabaseName
}
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", dis.Config.DistilleryBookkeepingDatabase)
if !dis.sqlRaw(createDBSQL) {
createDBSQL := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS `%s`;", sql.dis.Config.DistilleryBookkeepingDatabase)
if !sql.Query(createDBSQL) {
return errSQLUnableToCreate
}
}
// wait for the database to come up
logging.LogMessage(io, "Waiting for database update to be complete")
dis.SQLWaitForConnection()
sql.Wait()
// open the database
logging.LogMessage(io, "Migrating bookkeeping table")
{
db, err := dis.sqlBkTable(false)
db, err := sql.OpenBookkeeping(false)
if err != nil {
return fmt.Errorf("unable to access bookkeeping table: %s", err)
}

23
env/stack_ssh.go vendored
View file

@ -2,11 +2,24 @@ package env
import "github.com/FAU-CDI/wisski-distillery/internal/stack"
func (dis *Distillery) SSHStack() stack.Installable {
// TODO: Ensure that .env is copied if needed
return dis.asCoreStack("ssh", stack.Installable{})
// SSHComponent represents the 'ssh' layer belonging to a distillery
type SSHComponent struct {
dis *Distillery
}
func (dis *Distillery) SSHStackPath() string {
return dis.SSHStack().Dir
// SSH returns the SSHComponent belonging to this distillery
func (dis *Distillery) SSH() SSHComponent {
return SSHComponent{dis: dis}
}
func (SSHComponent) Name() string {
return "ssh"
}
func (ssh SSHComponent) Stack() stack.Installable {
return ssh.dis.makeComponentStack(ssh, stack.Installable{})
}
func (ssh SSHComponent) Path() string {
return ssh.Stack().Dir
}

View file

@ -20,8 +20,31 @@ import (
"github.com/tkw1536/goprogram/stream"
)
func (dis *Distillery) TriplestoreStack() stack.Installable {
return dis.asCoreStack("triplestore", stack.Installable{
// TriplestoreComponent represents the triplestore belonging to a distillery
type TriplestoreComponent struct {
BaseURL string // the base url of the api
PollInterval time.Duration // duration to wait during wait!
dis *Distillery
}
// Triplestore returns the TriplestoreComponent belonging to this distillery
func (dis *Distillery) Triplestore() TriplestoreComponent {
return TriplestoreComponent{
BaseURL: "http://127.0.0.1:7200",
PollInterval: time.Second,
dis: dis,
}
}
func (TriplestoreComponent) Name() string {
return "triplestore"
}
// Stack returns the installable Triplestore stack
func (ts TriplestoreComponent) Stack() stack.Installable {
return ts.dis.makeComponentStack(ts, stack.Installable{
CopyContextFiles: []string{"graphdb.zip"},
MakeDirsPerm: fs.ModeDir | fs.ModePerm,
@ -33,8 +56,8 @@ func (dis *Distillery) TriplestoreStack() stack.Installable {
})
}
func (dis *Distillery) TriplestoreStackPath() string {
return dis.TriplestoreStack().Dir
func (ts TriplestoreComponent) Path() string {
return ts.Stack().Dir
}
type TriplestoreUserPayload struct {
@ -50,14 +73,11 @@ type TriplestoreUserAppSettings struct {
ExecuteCount bool `json:"EXECUTE_COUNT"`
}
const triplestoreBaseURL = "http://127.0.0.1:7200"
const waitTSInterval = 1 * time.Second
// triplestoreCall makes a request to the triplestore.
// OpenRaw makes an http request to the triplestore api.
//
// When bodyName is non-empty, expect body to be a byte slice representing a multipart/form-data upload with the given name.
// When bodyName is empty, simply marshal body as application/json
func (dis *Distillery) triplestoreRequest(method, url string, body interface{}, bodyName string, accept string) (*http.Response, error) {
func (ts TriplestoreComponent) OpenRaw(method, url string, body interface{}, bodyName string, accept string) (*http.Response, error) {
var reader io.Reader
var contentType string
@ -87,7 +107,7 @@ func (dis *Distillery) triplestoreRequest(method, url string, body interface{},
}
// create the request object
req, err := http.NewRequest(method, triplestoreBaseURL+url, reader)
req, err := http.NewRequest(method, ts.BaseURL+url, reader)
if err != nil {
return nil, err
}
@ -99,21 +119,23 @@ func (dis *Distillery) triplestoreRequest(method, url string, body interface{},
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
req.SetBasicAuth(dis.Config.TriplestoreAdminUser, dis.Config.TriplestoreAdminPassword)
req.SetBasicAuth(ts.dis.Config.TriplestoreAdminUser, ts.dis.Config.TriplestoreAdminPassword)
// and send it
return http.DefaultClient.Do(req)
}
func (dis *Distillery) TriplestoreWaitForConnection() error {
// Wait waits for the connection to the Triplestore to succeed.
// This is achieved using a polling strategy.
func (ts TriplestoreComponent) Wait() error {
return wait.Wait(func() bool {
res, err := dis.triplestoreRequest("GET", "/rest/repositories", nil, "", "")
res, err := ts.OpenRaw("GET", "/rest/repositories", nil, "", "")
if err != nil {
return false
}
defer res.Body.Close()
return true
}, waitTSInterval, dis.Context())
}, ts.PollInterval, ts.dis.Context())
}
var errTripleStoreFailedRepository = exit.Error{
@ -121,8 +143,8 @@ var errTripleStoreFailedRepository = exit.Error{
ExitCode: exit.ExitGeneric,
}
func (dis *Distillery) TriplestoreProvision(name, domain, user, password string) error {
if err := dis.TriplestoreWaitForConnection(); err != nil {
func (ts TriplestoreComponent) Provision(name, domain, user, password string) error {
if err := ts.Wait(); err != nil {
return err
}
@ -137,7 +159,7 @@ func (dis *Distillery) TriplestoreProvision(name, domain, user, password string)
// do the create!
{
res, err := dis.triplestoreRequest("POST", "/rest/repositories", createRepo, "config", "")
res, err := ts.OpenRaw("POST", "/rest/repositories", createRepo, "config", "")
if err != nil {
return errTripleStoreFailedRepository.WithMessageF(err)
}
@ -149,7 +171,7 @@ func (dis *Distillery) TriplestoreProvision(name, domain, user, password string)
// create the user and grant them access
{
res, err := dis.triplestoreRequest("POST", "/rest/security/users/"+user, TriplestoreUserPayload{
res, err := ts.OpenRaw("POST", "/rest/security/users/"+user, TriplestoreUserPayload{
Password: password,
AppSettings: TriplestoreUserAppSettings{
DefaultInference: true,
@ -177,8 +199,8 @@ func (dis *Distillery) TriplestoreProvision(name, domain, user, password string)
}
// TriplestorePurgeUser deletes the specified user from the triplestore
func (dis *Distillery) TriplestorePurgeUser(user string) error {
res, err := dis.triplestoreRequest("DELETE", "/rest/security/users/"+user, nil, "", "")
func (ts TriplestoreComponent) PurgeUser(user string) error {
res, err := ts.OpenRaw("DELETE", "/rest/security/users/"+user, nil, "", "")
if err != nil {
return err
}
@ -189,8 +211,8 @@ func (dis *Distillery) TriplestorePurgeUser(user string) error {
}
// TriplestorePurgeRepo deletes the specified repo from the triplestore
func (dis *Distillery) TriplestorePurgeRepo(repo string) error {
res, err := dis.triplestoreRequest("DELETE", "/rest/repositories/"+repo, nil, "", "")
func (ts TriplestoreComponent) PurgeRepo(repo string) error {
res, err := ts.OpenRaw("DELETE", "/rest/repositories/"+repo, nil, "", "")
if err != nil {
return err
}
@ -203,8 +225,8 @@ func (dis *Distillery) TriplestorePurgeRepo(repo string) error {
var errTSBackupWrongStatusCode = errors.New("Distillery.Backup: Wrong status code")
// TriplestoreBackup backs up the repository named repo into the writer dst.
func (dis *Distillery) TriplestoreBackup(dst io.Writer, repo string) (int64, error) {
res, err := dis.triplestoreRequest("GET", "/repositories/"+repo+"/statements?infer=false", nil, "", "application/n-quads")
func (ts TriplestoreComponent) Backup(dst io.Writer, repo string) (int64, error) {
res, err := ts.OpenRaw("GET", "/repositories/"+repo+"/statements?infer=false", nil, "", "application/n-quads")
if err != nil {
return 0, err
}
@ -217,16 +239,16 @@ func (dis *Distillery) TriplestoreBackup(dst io.Writer, repo string) (int64, err
var errTriplestoreFailedSecurity = errors.New("failed to enable triplestore security: request did not succeed with HTTP 200 OK")
func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
func (ts TriplestoreComponent) Bootstrap(io stream.IOStream) error {
logging.LogMessage(io, "Waiting for Triplestore")
if err := dis.TriplestoreWaitForConnection(); err != nil {
if err := ts.Wait(); err != nil {
return err
}
logging.LogMessage(io, "Resetting admin user password")
{
res, err := dis.triplestoreRequest("PUT", "/rest/security/users/"+dis.Config.TriplestoreAdminUser, TriplestoreUserPayload{
Password: dis.Config.TriplestoreAdminPassword,
res, err := ts.OpenRaw("PUT", "/rest/security/users/"+ts.dis.Config.TriplestoreAdminUser, TriplestoreUserPayload{
Password: ts.dis.Config.TriplestoreAdminPassword,
AppSettings: TriplestoreUserAppSettings{
DefaultInference: true,
DefaultVisGraphSchema: true,
@ -257,7 +279,7 @@ func (dis *Distillery) TriplestoreBootstrap(io stream.IOStream) error {
logging.LogMessage(io, "Enabling Triplestore security")
{
res, err := dis.triplestoreRequest("POST", "/rest/security", true, "", "")
res, err := ts.OpenRaw("POST", "/rest/security", true, "", "")
if err != nil {
return fmt.Errorf("failed to enable triplestore security: %s", err)
}

24
env/stack_web.go vendored
View file

@ -2,14 +2,28 @@ package env
import "github.com/FAU-CDI/wisski-distillery/internal/stack"
func (dis *Distillery) WebStack() stack.Installable {
return dis.asCoreStack("web", stack.Installable{
// WebComponent represents the 'web' layer belonging to a distillery
type WebComponent struct {
dis *Distillery
}
// Web returns the WebComponent belonging to this distillery
func (dis *Distillery) Web() WebComponent {
return WebComponent{dis: dis}
}
func (WebComponent) Name() string {
return "web"
}
func (web WebComponent) Stack() stack.Installable {
return web.dis.makeComponentStack(web, stack.Installable{
EnvFileContext: map[string]string{
"DEFAULT_HOST": dis.Config.DefaultDomain,
"DEFAULT_HOST": web.dis.Config.DefaultDomain,
},
})
}
func (dis *Distillery) WebStackPath() string {
return dis.WebStack().Dir
func (web WebComponent) Path() string {
return web.Stack().Dir
}