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"` }