183 lines
3.8 KiB
Go
183 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type AppModule struct {
|
|
Name string
|
|
Folder string
|
|
CheckS string
|
|
}
|
|
|
|
type AppModuleConfig struct {
|
|
Name string `yaml:"name"`
|
|
CheckUrl *string `yaml:"check-url"`
|
|
}
|
|
|
|
type Script struct {
|
|
Name string
|
|
AbsPath string
|
|
Runner ScriptRunner
|
|
}
|
|
|
|
func (s *Script) Run() (string, error) {
|
|
args := runnerArgs(s.Runner.Runner, s.AbsPath)
|
|
if len(args) == 0 {
|
|
return "", errors.New("runner command is empty")
|
|
}
|
|
|
|
cmd := exec.Command(args[0], args[1:]...)
|
|
output, err := cmd.CombinedOutput()
|
|
return string(output), err
|
|
}
|
|
|
|
func runnerArgs(template string, scriptPath string) []string {
|
|
fields := strings.Fields(template)
|
|
for i, field := range fields {
|
|
fields[i] = strings.ReplaceAll(field, "%v", scriptPath)
|
|
}
|
|
return fields
|
|
}
|
|
|
|
func (m *AppModule) HasScript(name string, subfolder *string) (bool, *Script) {
|
|
folder := m.Folder
|
|
if subfolder != nil {
|
|
folder = filepath.Join(folder, *subfolder)
|
|
}
|
|
|
|
for _, r := range runners {
|
|
ext := r.Extension
|
|
if ext != "" && !strings.HasPrefix(ext, ".") {
|
|
ext = "." + ext
|
|
}
|
|
|
|
scriptPath := filepath.Join(folder, name+ext)
|
|
if fileExists(scriptPath) {
|
|
abs, err := filepath.Abs(scriptPath)
|
|
if err != nil {
|
|
return false, nil
|
|
}
|
|
return true, &Script{Name: name, AbsPath: abs, Runner: r}
|
|
}
|
|
}
|
|
return false, nil
|
|
}
|
|
func (m *AppModule) Check() (bool, string, error) {
|
|
if strings.HasPrefix(m.CheckS, "URL ") {
|
|
check := strings.Split(m.CheckS, " ")[1:]
|
|
if len(check) < 1 || len(check) > 3 {
|
|
return false, "", errors.New("check url is bad")
|
|
}
|
|
checkUrl := check[0]
|
|
code := ""
|
|
if len(check) > 1 {
|
|
code = check[1]
|
|
}
|
|
body := ""
|
|
if len(check) > 2 {
|
|
dBody, err := url.QueryUnescape(check[2])
|
|
if err != nil {
|
|
return false, "", errors.New("check body decode failed")
|
|
}
|
|
body = dBody
|
|
}
|
|
|
|
cCode, cBody, err := fetch(checkUrl, defaultFetchTimeout)
|
|
if err != nil {
|
|
return false, "", err
|
|
}
|
|
if code != "" && strconv.Itoa(cCode) != code {
|
|
return false, "", fmt.Errorf("code is different: expected %s, got %d", code, cCode)
|
|
}
|
|
if body != "" && body != cBody {
|
|
return false, "", errors.New("body is different")
|
|
}
|
|
|
|
return true, "", nil
|
|
|
|
} else {
|
|
exists, script := m.HasScript("check", nil)
|
|
if exists && script != nil {
|
|
output, err := script.Run()
|
|
if err != nil {
|
|
return false, output, err
|
|
} else {
|
|
return true, output, nil
|
|
}
|
|
} else {
|
|
return false, "", errors.New("check script not found")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *AppModule) Start() (string, error) {
|
|
exists, script := m.HasScript("start", nil)
|
|
if exists && script != nil {
|
|
return script.Run()
|
|
} else {
|
|
return "", errors.New("start script not found")
|
|
}
|
|
}
|
|
|
|
func (m *AppModule) Stop() (string, error) {
|
|
exists, script := m.HasScript("stop", nil)
|
|
if exists && script != nil {
|
|
return script.Run()
|
|
} else {
|
|
return "", errors.New("stop script not found")
|
|
}
|
|
}
|
|
|
|
func (m *AppModule) Restart() (string, error) {
|
|
exists, script := m.HasScript("restart", nil)
|
|
if exists && script != nil {
|
|
return script.Run()
|
|
} else {
|
|
stopOutput, err := m.Stop()
|
|
if err != nil {
|
|
return stopOutput, err
|
|
}
|
|
startOutput, err := m.Start()
|
|
return joinOutput(stopOutput, startOutput), err
|
|
}
|
|
|
|
}
|
|
|
|
func (m *AppModule) Fix() (string, error) {
|
|
exists, script := m.HasScript("fix", nil)
|
|
|
|
if exists && script != nil {
|
|
return script.Run()
|
|
} else {
|
|
return m.Restart()
|
|
}
|
|
}
|
|
|
|
func (m *AppModule) Run(scriptN string) (string, error) {
|
|
var sub = "run"
|
|
exists, script := m.HasScript(scriptN, &sub)
|
|
|
|
if exists && script != nil {
|
|
return script.Run()
|
|
} else {
|
|
return "", errors.New("run script not found")
|
|
}
|
|
}
|
|
|
|
type Application struct {
|
|
Name string
|
|
Folder string
|
|
AppModules []AppModule
|
|
}
|
|
|
|
type AppConfig struct {
|
|
Name string `yaml:"name"`
|
|
}
|