mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-07 14:50:55 +03:00
add support for inter-node communications
Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -187,6 +187,7 @@ var (
|
||||
sqlTableEventsRules string
|
||||
sqlTableRulesActionsMapping string
|
||||
sqlTableTasks string
|
||||
sqlTableNodes string
|
||||
sqlTableSchemaVersion string
|
||||
argon2Params *argon2id.Params
|
||||
lastLoginMinDelay = 10 * time.Minute
|
||||
@@ -216,6 +217,7 @@ func initSQLTables() {
|
||||
sqlTableEventsRules = "events_rules"
|
||||
sqlTableRulesActionsMapping = "rules_actions_mapping"
|
||||
sqlTableTasks = "tasks"
|
||||
sqlTableNodes = "nodes"
|
||||
sqlTableSchemaVersion = "schema_version"
|
||||
}
|
||||
|
||||
@@ -311,7 +313,7 @@ type ProviderStatus struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// Config provider configuration
|
||||
// Config defines the provider configuration
|
||||
type Config struct {
|
||||
// Driver name, must be one of the SupportedProviders
|
||||
Driver string `json:"driver" mapstructure:"driver"`
|
||||
@@ -460,6 +462,9 @@ type Config struct {
|
||||
// For shared data providers, active transfers are persisted in the database and thus
|
||||
// quota checks between ongoing transfers will work cross multiple instances
|
||||
IsShared int `json:"is_shared" mapstructure:"is_shared"`
|
||||
// Node defines the configuration for this cluster node.
|
||||
// Ignored if the provider is not shared/shareable
|
||||
Node NodeConfig `json:"node" mapstructure:"node"`
|
||||
// Path to the backup directory. This can be an absolute path or a path relative to the config dir
|
||||
BackupsPath string `json:"backups_path" mapstructure:"backups_path"`
|
||||
}
|
||||
@@ -778,6 +783,11 @@ type Provider interface {
|
||||
updateTaskTimestamp(name string) error
|
||||
setFirstDownloadTimestamp(username string) error
|
||||
setFirstUploadTimestamp(username string) error
|
||||
addNode() error
|
||||
getNodeByName(name string) (Node, error)
|
||||
getNodes() ([]Node, error)
|
||||
updateNodeTimestamp() error
|
||||
cleanupNodes() error
|
||||
checkAvailability() error
|
||||
close() error
|
||||
reloadConfig() error
|
||||
@@ -801,7 +811,6 @@ func checkSharedMode() {
|
||||
// Initialize the data provider.
|
||||
// An error is returned if the configured driver is invalid or if the data provider cannot be initialized
|
||||
func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
||||
var err error
|
||||
config = cnf
|
||||
checkSharedMode()
|
||||
config.Actions.ExecuteOn = util.RemoveDuplicates(config.Actions.ExecuteOn, true)
|
||||
@@ -812,19 +821,33 @@ func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
||||
return fmt.Errorf("required directory is invalid, backup path %#v", cnf.BackupsPath)
|
||||
}
|
||||
|
||||
if err = initializeHashingAlgo(&cnf); err != nil {
|
||||
if err := initializeHashingAlgo(&cnf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = validateHooks(); err != nil {
|
||||
if err := validateHooks(); err != nil {
|
||||
return err
|
||||
}
|
||||
err = createProvider(basePath)
|
||||
if err := createProvider(basePath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkDatabase(checkAdmins); err != nil {
|
||||
return err
|
||||
}
|
||||
admins, err := provider.getAdmins(1, 0, OrderASC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cnf.UpdateMode == 0 {
|
||||
err = provider.initializeDatabase()
|
||||
isAdminCreated.Store(len(admins) > 0)
|
||||
if err := config.Node.validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
delayedQuotaUpdater.start()
|
||||
return startScheduler()
|
||||
}
|
||||
|
||||
func checkDatabase(checkAdmins bool) error {
|
||||
if config.UpdateMode == 0 {
|
||||
err := provider.initializeDatabase()
|
||||
if err != nil && err != ErrNoInitRequired {
|
||||
logger.WarnToConsole("Unable to initialize data provider: %v", err)
|
||||
providerLog(logger.LevelError, "Unable to initialize data provider: %v", err)
|
||||
@@ -838,7 +861,7 @@ func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
||||
providerLog(logger.LevelError, "database migration error: %v", err)
|
||||
return err
|
||||
}
|
||||
if checkAdmins && cnf.CreateDefaultAdmin {
|
||||
if checkAdmins && config.CreateDefaultAdmin {
|
||||
err = checkDefaultAdmin()
|
||||
if err != nil {
|
||||
providerLog(logger.LevelError, "erro checking the default admin: %v", err)
|
||||
@@ -848,13 +871,7 @@ func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
||||
} else {
|
||||
providerLog(logger.LevelInfo, "database initialization/migration skipped, manual mode is configured")
|
||||
}
|
||||
admins, err := provider.getAdmins(1, 0, OrderASC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isAdminCreated.Store(len(admins) > 0)
|
||||
delayedQuotaUpdater.start()
|
||||
return startScheduler()
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateHooks() error {
|
||||
@@ -937,15 +954,17 @@ func validateSQLTablesPrefix() error {
|
||||
sqlTableEventsRules = config.SQLTablesPrefix + sqlTableEventsRules
|
||||
sqlTableRulesActionsMapping = config.SQLTablesPrefix + sqlTableRulesActionsMapping
|
||||
sqlTableTasks = config.SQLTablesPrefix + sqlTableTasks
|
||||
sqlTableNodes = config.SQLTablesPrefix + sqlTableNodes
|
||||
sqlTableSchemaVersion = config.SQLTablesPrefix + sqlTableSchemaVersion
|
||||
providerLog(logger.LevelDebug, "sql table for users %q, folders %q users folders mapping %q admins %q "+
|
||||
"api keys %q shares %q defender hosts %q defender events %q transfers %q groups %q "+
|
||||
"users groups mapping %q admins groups mapping %q groups folders mapping %q shared sessions %q "+
|
||||
"schema version %q events actions %q events rules %q rules actions mapping %q tasks %q",
|
||||
"schema version %q events actions %q events rules %q rules actions mapping %q tasks %q nodes %q",
|
||||
sqlTableUsers, sqlTableFolders, sqlTableUsersFoldersMapping, sqlTableAdmins, sqlTableAPIKeys,
|
||||
sqlTableShares, sqlTableDefenderHosts, sqlTableDefenderEvents, sqlTableActiveTransfers, sqlTableGroups,
|
||||
sqlTableUsersGroupsMapping, sqlTableAdminsGroupsMapping, sqlTableGroupsFoldersMapping, sqlTableSharedSessions,
|
||||
sqlTableSchemaVersion, sqlTableEventsActions, sqlTableEventsRules, sqlTableRulesActionsMapping, sqlTableTasks)
|
||||
sqlTableSchemaVersion, sqlTableEventsActions, sqlTableEventsRules, sqlTableRulesActionsMapping,
|
||||
sqlTableTasks, sqlTableNodes)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1728,6 +1747,29 @@ func UpdateTaskTimestamp(name string) error {
|
||||
return provider.updateTaskTimestamp(name)
|
||||
}
|
||||
|
||||
// GetNodes returns the other cluster nodes
|
||||
func GetNodes() ([]Node, error) {
|
||||
if currentNode == nil {
|
||||
return nil, nil
|
||||
}
|
||||
nodes, err := provider.getNodes()
|
||||
if err != nil {
|
||||
providerLog(logger.LevelError, "unable to get other cluster nodes %v", err)
|
||||
}
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
// GetNodeByName returns a node, different from the current one, by name
|
||||
func GetNodeByName(name string) (Node, error) {
|
||||
if currentNode == nil {
|
||||
return Node{}, util.NewRecordNotFoundError(errNoClusterNodes.Error())
|
||||
}
|
||||
if name == currentNode.Name {
|
||||
return Node{}, util.NewValidationError(fmt.Sprintf("%s is the current node, it must refer to other nodes", name))
|
||||
}
|
||||
return provider.getNodeByName(name)
|
||||
}
|
||||
|
||||
// HasAdmin returns true if the first admin has been created
|
||||
// and so SFTPGo is ready to be used
|
||||
func HasAdmin() bool {
|
||||
|
||||
Reference in New Issue
Block a user