Add 'dis' component
This commit adds a new 'dis' component to the distillery that serves a list of all known instances for the moment.
This commit is contained in:
parent
35bb95c5ca
commit
4b357476a3
43 changed files with 434 additions and 167 deletions
6
env/component.go
vendored
6
env/component.go
vendored
|
|
@ -10,11 +10,12 @@ import (
|
|||
|
||||
// Stacks returns the Stacks of this distillery
|
||||
func (dis *Distillery) Components() []Component {
|
||||
// TODO: Do we want to cache these stacks?
|
||||
// TODO: Do we want to cache these components?
|
||||
return []Component{
|
||||
dis.Web(),
|
||||
dis.Self(),
|
||||
dis.Resolver(),
|
||||
dis.Dis(),
|
||||
dis.SSH(),
|
||||
dis.Triplestore(),
|
||||
dis.SQL(),
|
||||
|
|
@ -25,7 +26,8 @@ func (dis *Distillery) Components() []Component {
|
|||
type Component interface {
|
||||
Name() string // Name is the name of this component
|
||||
|
||||
Stack() stack.Installable // Stack returns the installable stack representing this component
|
||||
Stack() stack.Installable // Stack returns the installable stack representing this component
|
||||
Context(parent stack.InstallationContext) stack.InstallationContext // context for installation
|
||||
|
||||
Path() string // Path returns the path to this component
|
||||
}
|
||||
|
|
|
|||
47
env/component_dis.go
vendored
Normal file
47
env/component_dis.go
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"github.com/FAU-CDI/wisski-distillery/core"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/stack"
|
||||
)
|
||||
|
||||
// DisComponent represents the 'dis' layer belonging to a distillery
|
||||
type DisComponent struct {
|
||||
dis *Distillery
|
||||
}
|
||||
|
||||
// Dis returns the DisComponent belonging to this distillery
|
||||
func (dis *Distillery) Dis() DisComponent {
|
||||
return DisComponent{dis: dis}
|
||||
}
|
||||
|
||||
func (DisComponent) Name() string {
|
||||
return "dis"
|
||||
}
|
||||
|
||||
func (dis DisComponent) Stack() stack.Installable {
|
||||
return dis.dis.makeComponentStack(dis, stack.Installable{
|
||||
EnvFileContext: map[string]string{
|
||||
"VIRTUAL_HOST": dis.dis.DefaultVirtualHost(),
|
||||
"LETSENCRYPT_HOST": dis.dis.DefaultLetsencryptHost(),
|
||||
"LETSENCRYPT_EMAIL": dis.dis.Config.CertbotEmail,
|
||||
|
||||
"CONFIG_PATH": dis.dis.Config.ConfigPath,
|
||||
"DEPLOY_ROOT": dis.dis.Config.DeployRoot,
|
||||
|
||||
"GLOBAL_AUTHORIZED_KEYS_FILE": dis.dis.Config.GlobalAuthorizedKeysFile,
|
||||
"SELF_OVERRIDES_FILE": dis.dis.Config.SelfOverridesFile,
|
||||
},
|
||||
CopyContextFiles: []string{core.Executable},
|
||||
})
|
||||
}
|
||||
|
||||
func (dis DisComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return stack.InstallationContext{
|
||||
core.Executable: dis.dis.CurrentExecutable(),
|
||||
}
|
||||
}
|
||||
|
||||
func (dis DisComponent) Path() string {
|
||||
return dis.Stack().Dir
|
||||
}
|
||||
4
env/component_resolver.go
vendored
4
env/component_resolver.go
vendored
|
|
@ -44,6 +44,10 @@ func (resolver ResolverComponent) Stack() stack.Installable {
|
|||
return stack
|
||||
}
|
||||
|
||||
func (ResolverComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
func (resolver ResolverComponent) Path() string {
|
||||
return resolver.Stack().Dir
|
||||
}
|
||||
|
|
|
|||
4
env/component_self.go
vendored
4
env/component_self.go
vendored
|
|
@ -16,6 +16,10 @@ func (SelfComponent) Name() string {
|
|||
return "self"
|
||||
}
|
||||
|
||||
func (SelfComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
func (sc SelfComponent) Stack() stack.Installable {
|
||||
TARGET := "https://github.com/FAU-CDI/wisski-distillery"
|
||||
if sc.dis.Config.SelfRedirect != nil {
|
||||
|
|
|
|||
9
env/component_sql.go
vendored
9
env/component_sql.go
vendored
|
|
@ -20,6 +20,8 @@ import (
|
|||
|
||||
// SQLComponent represents the 'sql' layer belonging to a distillery
|
||||
type SQLComponent struct {
|
||||
ServerURL string
|
||||
|
||||
PollInterval time.Duration // Duration to wait for during wait
|
||||
|
||||
dis *Distillery
|
||||
|
|
@ -28,6 +30,7 @@ type SQLComponent struct {
|
|||
// SSH returns the SSHComponent belonging to this distillery
|
||||
func (dis *Distillery) SQL() SQLComponent {
|
||||
return SQLComponent{
|
||||
ServerURL: dis.Upstream.SQL,
|
||||
PollInterval: time.Second,
|
||||
|
||||
dis: dis,
|
||||
|
|
@ -38,6 +41,10 @@ func (SQLComponent) Name() string {
|
|||
return "sql"
|
||||
}
|
||||
|
||||
func (SQLComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
// Stack returns the docker stack that handles the sql database.
|
||||
func (sql SQLComponent) Stack() stack.Installable {
|
||||
return sql.dis.makeComponentStack(sql, stack.Installable{
|
||||
|
|
@ -56,7 +63,7 @@ func (sql SQLComponent) Path() string {
|
|||
// sqlOpen opens a new sql connection to the provided database using the administrative credentials
|
||||
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),
|
||||
DSN: fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=True&loc=Local", sql.dis.Config.MysqlAdminUser, sql.dis.Config.MysqlAdminPassword, sql.ServerURL, database),
|
||||
DefaultStringSize: 256,
|
||||
}
|
||||
|
||||
|
|
|
|||
4
env/component_ssh.go
vendored
4
env/component_ssh.go
vendored
|
|
@ -20,6 +20,10 @@ func (ssh SSHComponent) Stack() stack.Installable {
|
|||
return ssh.dis.makeComponentStack(ssh, stack.Installable{})
|
||||
}
|
||||
|
||||
func (SSHComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
func (ssh SSHComponent) Path() string {
|
||||
return ssh.Stack().Dir
|
||||
}
|
||||
|
|
|
|||
6
env/component_triplestore.go
vendored
6
env/component_triplestore.go
vendored
|
|
@ -32,7 +32,7 @@ type TriplestoreComponent struct {
|
|||
// Triplestore returns the TriplestoreComponent belonging to this distillery
|
||||
func (dis *Distillery) Triplestore() TriplestoreComponent {
|
||||
return TriplestoreComponent{
|
||||
BaseURL: "http://127.0.0.1:7200",
|
||||
BaseURL: "http://" + dis.Upstream.Triplestore,
|
||||
PollInterval: time.Second,
|
||||
|
||||
dis: dis,
|
||||
|
|
@ -43,6 +43,10 @@ func (TriplestoreComponent) Name() string {
|
|||
return "triplestore"
|
||||
}
|
||||
|
||||
func (TriplestoreComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
// Stack returns the installable Triplestore stack
|
||||
func (ts TriplestoreComponent) Stack() stack.Installable {
|
||||
return ts.dis.makeComponentStack(ts, stack.Installable{
|
||||
|
|
|
|||
4
env/component_web.go
vendored
4
env/component_web.go
vendored
|
|
@ -24,6 +24,10 @@ func (web WebComponent) Stack() stack.Installable {
|
|||
})
|
||||
}
|
||||
|
||||
func (WebComponent) Context(parent stack.InstallationContext) stack.InstallationContext {
|
||||
return parent
|
||||
}
|
||||
|
||||
func (web WebComponent) Path() string {
|
||||
return web.Stack().Dir
|
||||
}
|
||||
|
|
|
|||
23
env/constants.go
vendored
23
env/constants.go
vendored
|
|
@ -4,16 +4,13 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/core"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/fsx"
|
||||
)
|
||||
|
||||
// Executable is the name of the 'wdcli' executable.
|
||||
// It should be located inside the deployment directory.
|
||||
const Executable = "wdcli"
|
||||
|
||||
// ExecutablePath returns the path to the executable of this distillery.
|
||||
func (dis *Distillery) ExecutablePath() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, Executable)
|
||||
return filepath.Join(dis.Config.DeployRoot, core.Executable)
|
||||
}
|
||||
|
||||
// UsingDistilleryExecutable checks if the current process
|
||||
|
|
@ -25,12 +22,12 @@ func (dis *Distillery) UsingDistilleryExecutable() bool {
|
|||
return fsx.SameFile(exe, dis.ExecutablePath())
|
||||
}
|
||||
|
||||
// Config file is the name of the config file.
|
||||
// It should be located inside the deployment directory.
|
||||
const ConfigFile = ".env"
|
||||
|
||||
// ConfigFilePath returns the path to the configuration file of this distillery.
|
||||
// TODO: This should be moved to the Config struct.
|
||||
func (dis *Distillery) ConfigFilePath() string {
|
||||
return filepath.Join(dis.Config.DeployRoot, ConfigFile)
|
||||
// CurrentExecutable returns the path to the current executable being used.
|
||||
// When it does not exist, falls back to the default executable.
|
||||
func (dis *Distillery) CurrentExecutable() string {
|
||||
exe, err := os.Executable()
|
||||
if err != nil || !fsx.IsFile(exe) {
|
||||
return dis.ExecutablePath()
|
||||
}
|
||||
return exe
|
||||
}
|
||||
|
|
|
|||
38
env/distillery.go
vendored
38
env/distillery.go
vendored
|
|
@ -5,13 +5,21 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/core"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/config"
|
||||
"github.com/tkw1536/goprogram/exit"
|
||||
)
|
||||
|
||||
// Distillery represents a running instance for the distillery
|
||||
type Distillery struct {
|
||||
Config *config.Config
|
||||
Config *config.Config
|
||||
Upstream Upstream
|
||||
}
|
||||
|
||||
// Upstream are the upstream urls connecting to the various external components.
|
||||
type Upstream struct {
|
||||
SQL string
|
||||
Triplestore string
|
||||
}
|
||||
|
||||
func (dis Distillery) HTTPSEnabled() bool {
|
||||
|
|
@ -50,28 +58,44 @@ var errOpenConfig = exit.Error{
|
|||
}
|
||||
|
||||
// NewDistillery creates a new distillery object from a set of parameters and requirements
|
||||
func NewDistillery(params Params, req Requirements) (env *Distillery, err error) {
|
||||
env = &Distillery{}
|
||||
func NewDistillery(params core.Params, flags core.Flags, req core.Requirements) (env *Distillery, err error) {
|
||||
env = &Distillery{
|
||||
Upstream: Upstream{
|
||||
SQL: "127.0.0.1:3306",
|
||||
Triplestore: "127.0.0.1:7200",
|
||||
},
|
||||
}
|
||||
|
||||
if flags.InternalInDocker {
|
||||
env.Upstream.SQL = "sql:3306"
|
||||
env.Upstream.Triplestore = "triplestore:7200"
|
||||
}
|
||||
|
||||
// if we don't need to load the config, there is nothing to do
|
||||
if !req.NeedsDistillery {
|
||||
return
|
||||
}
|
||||
|
||||
// if there is no no config file, return
|
||||
cfg := params.ConfigFilePath()
|
||||
// try to find the configuration file
|
||||
cfg := flags.ConfigPath // command line flags first
|
||||
if cfg == "" {
|
||||
cfg = params.ConfigPath // then globally provided files
|
||||
}
|
||||
if cfg == "" {
|
||||
return nil, errNoConfigFile
|
||||
}
|
||||
|
||||
f, err := os.Open(params.ConfigFilePath())
|
||||
// open the config file!
|
||||
f, err := os.Open(params.ConfigPath)
|
||||
if err != nil {
|
||||
return nil, errOpenConfig.WithMessageF(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// unmarshal the config
|
||||
env.Config = &config.Config{}
|
||||
env.Config = &config.Config{
|
||||
ConfigPath: cfg,
|
||||
}
|
||||
err = env.Config.Unmarshal(f)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
92
env/params.go
vendored
92
env/params.go
vendored
|
|
@ -1,92 +0,0 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tkw1536/goprogram/exit"
|
||||
)
|
||||
|
||||
// Params are parameters used for initialization of the environment
|
||||
type Params struct {
|
||||
BaseDirectory string
|
||||
}
|
||||
|
||||
// ConfigFilePath returns the path to the configuration file
|
||||
func (params Params) ConfigFilePath() string {
|
||||
if params.BaseDirectory == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(params.BaseDirectory, ConfigFile)
|
||||
}
|
||||
|
||||
var errUnableToLoadParams = exit.Error{
|
||||
ExitCode: exit.ExitGeneralArguments,
|
||||
Message: "Unable to configure wdcli environment: %s",
|
||||
}
|
||||
|
||||
const BaseDirectoryDefault = "/var/www/deploy"
|
||||
|
||||
// ParamsFromEnv creates a new set of parameters from the environment.
|
||||
// There is no guarantee that the parameters are valid.
|
||||
func ParamsFromEnv() (params Params, err error) {
|
||||
// try to read the base directory
|
||||
value, err := ReadBaseDirectory()
|
||||
switch {
|
||||
case os.IsNotExist(err):
|
||||
params.BaseDirectory = BaseDirectoryDefault
|
||||
case err == nil:
|
||||
params.BaseDirectory = value
|
||||
default:
|
||||
return params, errUnableToLoadParams.WithMessageF(err)
|
||||
}
|
||||
|
||||
return params, nil
|
||||
}
|
||||
|
||||
var baseConfigFile = ".wdcli"
|
||||
|
||||
// ReadBaseDirectory reads the base directory from the environment, or an empty string
|
||||
func ReadBaseDirectory() (value string, err error) {
|
||||
// find the current user
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// read the base config file!
|
||||
contents, err := os.ReadFile(filepath.Join(usr.HomeDir, baseConfigFile))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// and trim the spaces!
|
||||
value = strings.TrimSpace(string(contents))
|
||||
|
||||
// check that it is actually set!
|
||||
if len(value) == 0 {
|
||||
return "", errors.New("ReadBaseDirectory: Directory is empty")
|
||||
}
|
||||
|
||||
// and return it!
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// WriteBaseDirectory writes the base directory to the environment, or returns an error
|
||||
func WriteBaseDirectory(dir string) error {
|
||||
// find the current user
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// read the base config file!
|
||||
return os.WriteFile(
|
||||
filepath.Join(usr.HomeDir, baseConfigFile),
|
||||
[]byte(dir),
|
||||
os.ModePerm,
|
||||
)
|
||||
}
|
||||
25
env/requirements.go
vendored
25
env/requirements.go
vendored
|
|
@ -1,25 +0,0 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"github.com/tkw1536/goprogram"
|
||||
"github.com/tkw1536/goprogram/meta"
|
||||
)
|
||||
|
||||
type Requirements struct {
|
||||
// Do we need an installed distillery?
|
||||
NeedsDistillery bool
|
||||
}
|
||||
|
||||
// AllowsFlag checks if the provided flag may be passed to fullfill this requirement
|
||||
// By default it is used only for help page generation, and may be inaccurate.
|
||||
func (r Requirements) AllowsFlag(flag meta.Flag) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Validate validates if this requirement is fullfilled for the provided global flags.
|
||||
// It should return either nil, or an error of type exit.Error.
|
||||
//
|
||||
// Validate does not take into account AllowsOption, see ValidateAllowedOptions.
|
||||
func (r Requirements) Validate(arguments goprogram.Arguments[struct{}]) error {
|
||||
return nil
|
||||
}
|
||||
31
env/server.go
vendored
Normal file
31
env/server.go
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package env
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Server represents a server for this distillery
|
||||
type Server struct {
|
||||
dis *Distillery
|
||||
}
|
||||
|
||||
func (dis *Distillery) Server() *Server {
|
||||
return &Server{
|
||||
dis: dis,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
instances, err := s.dis.AllInstances()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
io.WriteString(w, "Something went wrong")
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
for _, instance := range instances {
|
||||
io.WriteString(w, instance.Slug+"\n")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue