176 lines
4.7 KiB
Go
176 lines
4.7 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"sync"
|
|
|
|
"gitea.suyono.dev/suyono/wingmate"
|
|
"github.com/spf13/viper"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const (
|
|
EnvPrefix = "WINGMATE"
|
|
ConfigPath = "config_path"
|
|
DefaultConfigPath = "/etc/wingmate"
|
|
ServiceDirName = "service"
|
|
CrontabFileName = "crontab"
|
|
WingmateConfigFileName = "wingmate"
|
|
WingmateConfigFileFormat = "yaml"
|
|
WingmateVersion = "APP_VERSION"
|
|
PidProxyPathConfig = "pidproxy_path"
|
|
PidProxyPathDefault = "wmpidproxy"
|
|
ExecPathConfig = "exec_path"
|
|
ExecPathDefault = "wmexec"
|
|
versionTrimRightCutSet = "\r\n "
|
|
VersionFlag = "version"
|
|
WMPidProxyPathFlag = "pid-proxy"
|
|
WMExecPathFlag = "exec"
|
|
ConfigPathFlag = "config"
|
|
VersionCheckKey = "check-version"
|
|
)
|
|
|
|
type Config struct {
|
|
ServiceV0 []string
|
|
CronV0 []*Cron
|
|
Service []ServiceTask
|
|
Cron []CronTask
|
|
viperMtx *sync.Mutex
|
|
}
|
|
|
|
type Task struct {
|
|
Command []string `mapstructure:"command"`
|
|
Environ []string `mapstructure:"environ"`
|
|
Setsid bool `mapstructure:"setsid"`
|
|
User string `mapstructure:"user"`
|
|
Group string `mapstructure:"group"`
|
|
WorkingDir string `mapstructure:"working_dir"`
|
|
}
|
|
|
|
type ServiceTask struct {
|
|
Task `mapstructure:",squash"`
|
|
Name string `mapstructure:"-"`
|
|
Background bool `mapstructure:"background"`
|
|
PidFile string `mapstructure:"pidfile"`
|
|
StartSecs uint `mapstructure:"startsecs"`
|
|
AutoStart bool `mapstructure:"autostart"`
|
|
AutoRestart bool `mapstructure:"autorestart"`
|
|
}
|
|
|
|
type CronTask struct {
|
|
CronSchedule `mapstructure:"-"`
|
|
Task `mapstructure:",squash"`
|
|
Name string `mapstructure:"-"`
|
|
Schedule string `mapstructure:"schedule"`
|
|
}
|
|
|
|
type CronSchedule struct {
|
|
Minute CronTimeSpec
|
|
Hour CronTimeSpec
|
|
DoM CronTimeSpec
|
|
Month CronTimeSpec
|
|
DoW CronTimeSpec
|
|
}
|
|
|
|
func SetVersion(version string) {
|
|
version = strings.TrimRight(version, versionTrimRightCutSet)
|
|
viper.Set(WingmateVersion, version)
|
|
wingmate.Log().Info().Msgf("starting wingmate version %s", version)
|
|
}
|
|
|
|
func Read() (*Config, error) {
|
|
viper.SetEnvPrefix(EnvPrefix)
|
|
_ = viper.BindEnv(ConfigPath)
|
|
_ = viper.BindEnv(PidProxyPathConfig)
|
|
_ = viper.BindEnv(ExecPathConfig)
|
|
viper.SetDefault(ConfigPath, DefaultConfigPath)
|
|
viper.SetDefault(PidProxyPathConfig, PidProxyPathDefault)
|
|
viper.SetDefault(ExecPathConfig, ExecPathDefault)
|
|
|
|
ParseFlags()
|
|
|
|
var (
|
|
dirent []os.DirEntry
|
|
err error
|
|
svcdir string
|
|
serviceAvailable bool
|
|
cronAvailable bool
|
|
wingmateConfigAvailable bool
|
|
cron []*Cron
|
|
crontabfile string
|
|
services []ServiceTask
|
|
crones []CronTask
|
|
)
|
|
|
|
serviceAvailable = false
|
|
cronAvailable = false
|
|
outConfig := &Config{
|
|
ServiceV0: make([]string, 0),
|
|
}
|
|
configPath := viper.GetString(ConfigPath)
|
|
svcdir = filepath.Join(configPath, ServiceDirName)
|
|
dirent, err = os.ReadDir(svcdir)
|
|
if err != nil {
|
|
wingmate.Log().Error().Msgf("encounter error when reading service directory %s: %+v", svcdir, err)
|
|
}
|
|
if len(dirent) > 0 {
|
|
for _, d := range dirent {
|
|
if d.Type().IsRegular() {
|
|
svcPath := filepath.Join(svcdir, d.Name())
|
|
if err = unix.Access(svcPath, unix.X_OK); err == nil {
|
|
serviceAvailable = true
|
|
outConfig.ServiceV0 = append(outConfig.ServiceV0, svcPath)
|
|
} else {
|
|
wingmate.Log().Error().Msgf("checking executable access for %s: %+v", svcPath, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
crontabfile = filepath.Join(configPath, CrontabFileName)
|
|
cron, err = readCrontab(crontabfile)
|
|
if len(cron) > 0 {
|
|
outConfig.CronV0 = cron
|
|
cronAvailable = true
|
|
}
|
|
if err != nil {
|
|
wingmate.Log().Error().Msgf("encounter error when reading crontab %s: %+v", crontabfile, err)
|
|
}
|
|
|
|
wingmateConfigAvailable = false
|
|
if services, crones, err = readConfigYaml(configPath, WingmateConfigFileName, WingmateConfigFileFormat); err != nil {
|
|
wingmate.Log().Error().Msgf("encounter error when reading wingmate config file in %s/%s: %+v", configPath, WingmateConfigFileName, err)
|
|
}
|
|
if len(services) > 0 {
|
|
outConfig.Service = services
|
|
wingmateConfigAvailable = true
|
|
}
|
|
if len(crones) > 0 {
|
|
outConfig.Cron = crones
|
|
wingmateConfigAvailable = true
|
|
}
|
|
|
|
if !serviceAvailable && !cronAvailable && !wingmateConfigAvailable {
|
|
return nil, errors.New("no config found")
|
|
}
|
|
|
|
return outConfig, nil
|
|
}
|
|
|
|
func (c *Config) WMPidProxyPath() string {
|
|
c.viperMtx.Lock()
|
|
defer c.viperMtx.Unlock()
|
|
|
|
return viper.GetString(PidProxyPathConfig)
|
|
}
|
|
|
|
func (c *Config) WMExecPath() string {
|
|
c.viperMtx.Lock()
|
|
defer c.viperMtx.Unlock()
|
|
|
|
return viper.GetString(ExecPathConfig)
|
|
}
|