write checker framework
Signed-off-by: Nathan13888 <29968201+Nathan13888@users.noreply.github.com>
This commit is contained in:
parent
4823e28fe0
commit
4502ee4171
|
@ -0,0 +1,115 @@
|
|||
package checkers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// "Projects" which have valid configs.
|
||||
var EnabledProjects = make(map[string]*Project)
|
||||
|
||||
// TODO: refactor all errors into variables
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Project, Project Properties, Project Checker
|
||||
|
||||
type Project struct {
|
||||
Name string
|
||||
Properties ProjectProperties
|
||||
NumOfCheckers int
|
||||
Checkers []*ProjectChecker
|
||||
}
|
||||
|
||||
type ProjectProperties struct {
|
||||
OOSSince time.Time //`json:"out_of_sync_since"`
|
||||
OOSInterval int64 `json:"out_of_sync_interval"` // in seconds
|
||||
CSC string `json:"csc"`
|
||||
Upstream string `json:"upstream"`
|
||||
File string `json:"file"`
|
||||
}
|
||||
|
||||
type ProjectChecker struct {
|
||||
CheckProject func() CheckerResult
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////////
|
||||
// Checker Status and Checker Result
|
||||
type CheckerStatus string
|
||||
|
||||
var CHECKER_SUCCESS CheckerStatus = "success"
|
||||
var CHECKER_PROGRESS CheckerStatus = "progress"
|
||||
var CHECKER_ERROR CheckerStatus = "error"
|
||||
var CHECKER_FAIL CheckerStatus = "fail"
|
||||
|
||||
type CheckerResult struct {
|
||||
ProjectName string `json:"project_name"`
|
||||
CheckerName string `json:"checker_name"`
|
||||
Time time.Time `json:"time"`
|
||||
Status CheckerStatus `json:"status"`
|
||||
Error error `json:"error"`
|
||||
}
|
||||
|
||||
type CheckerResultCallback func(CheckerResult)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Given a project, all checks are initiated.
|
||||
func (p Project) RunChecksAsync(callback CheckerResultCallback) error {
|
||||
checks := p.Checkers
|
||||
n := len(checks)
|
||||
|
||||
// TODO: assert other checkers?
|
||||
// assert if the number of checkers match the expected number of checkers
|
||||
if n != p.NumOfCheckers {
|
||||
return errors.New("Number of checkers does not match the expected number of checkers.")
|
||||
}
|
||||
|
||||
log.Info().Msgf("Running %d checks for project %s", n, p.Name)
|
||||
for i := 0; i < n; i++ {
|
||||
check := checks[i]
|
||||
log.Info().Str("project", p.Name).Msgf("Running check %d", i)
|
||||
|
||||
check.RunCheckAsync(callback)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Given a check, run the check asynchronously and call the callback function.
|
||||
func (c ProjectChecker) RunCheckAsync(callback CheckerResultCallback) error {
|
||||
go func() {
|
||||
res := c.CheckProject()
|
||||
callback(res)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Looks up a project by name, and returns only if the project is enabled.
|
||||
func GetProject(name string) (*Project, error) {
|
||||
res, exists := EnabledProjects[name]
|
||||
if !exists {
|
||||
return res, errors.New("Requested project not found.")
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Loads a project by name, and returns if the project is found.
|
||||
func LoadProject(name string) (*Project, error) {
|
||||
res, exists := SupportedProjects[name]
|
||||
if !exists {
|
||||
return res, errors.New("Requested project not found.")
|
||||
}
|
||||
if res.Properties == DefaultProjectProperties {
|
||||
log.Debug().Str("csc", res.Properties.CSC).
|
||||
Msgf("Requested project %s has default properties.", name)
|
||||
return res, errors.New("Requested project has invalid properties. Please check the project config.")
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Loading Project %s", name)
|
||||
EnabledProjects[name] = res
|
||||
return res, nil
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package checkers
|
||||
|
||||
var DebianProject Project = Project{
|
||||
Name: "debian",
|
||||
Properties: DefaultProjectProperties,
|
||||
NumOfCheckers: 1,
|
||||
Checkers: []*ProjectChecker{
|
||||
GetDefaultChecker("debian"),
|
||||
},
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package checkers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var DefaultProjectProperties = ProjectProperties{
|
||||
OOSSince: time.Now(),
|
||||
OOSInterval: 3600,
|
||||
CSC: "unknown",
|
||||
Upstream: "unknown",
|
||||
File: "unknown",
|
||||
}
|
||||
|
||||
var DefaultCheckerResult CheckerResult = CheckerResult{
|
||||
ProjectName: "unknown",
|
||||
CheckerName: "unknown",
|
||||
Status: CHECKER_PROGRESS,
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// All "projects" which have been implemented.
|
||||
var SupportedProjects map[string]*Project = map[string]*Project{
|
||||
"debian": &DebianProject,
|
||||
}
|
||||
|
||||
func LoadDefaultProjects() {
|
||||
// Load all projects that's implemented
|
||||
|
||||
log.Info().Msg("Loading Default Projects.")
|
||||
|
||||
LoadProject("debian")
|
||||
|
||||
}
|
||||
|
||||
func GetDefaultChecker(name string) *ProjectChecker {
|
||||
return &ProjectChecker{
|
||||
CheckProject: func() CheckerResult {
|
||||
// TODO: implement
|
||||
return DefaultCheckerResult
|
||||
},
|
||||
}
|
||||
}
|
|
@ -34,6 +34,14 @@ func LoadFromFile(path string) error {
|
|||
for proj, prop := range data {
|
||||
log.Info().Str("project", proj).Msg("Enabled Project.")
|
||||
|
||||
sp, exists := checkers.SupportedProjects[NormalizeName(proj)]
|
||||
if !exists {
|
||||
log.Warn().Str("project", proj).Msg("Project not supported.")
|
||||
continue
|
||||
}
|
||||
|
||||
sp.Properties = prop
|
||||
|
||||
log.Debug().
|
||||
Str("distribution", proj).
|
||||
// Time("out_of_sync_since", prop.OOSSince).
|
||||
|
|
65
main.go
65
main.go
|
@ -2,7 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Nathan13888/mirror-checker2/v2/checkers"
|
||||
"github.com/Nathan13888/mirror-checker2/v2/config"
|
||||
|
@ -11,17 +10,20 @@ import (
|
|||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func getAbsPath(path string) string {
|
||||
absPath, err := filepath.Abs(path)
|
||||
var configPath string
|
||||
|
||||
func loadConfig() {
|
||||
path := config.GetAbsPath(configPath)
|
||||
// TODO: check if file exists
|
||||
|
||||
log.Info().Str("path", path).Msg("Loading config file.")
|
||||
err := config.LoadFromFile(path)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get absolute path.")
|
||||
return path
|
||||
log.Fatal().Err(err).Msg("Failed to load config file.")
|
||||
}
|
||||
return absPath
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
config.SetupLogger(true) // TODO: flag for debug mode
|
||||
|
||||
// Start CLI
|
||||
|
@ -33,6 +35,16 @@ func main() {
|
|||
EnableBashCompletion: true,
|
||||
// https://cli.urfave.org/v2/examples/combining-short-options/
|
||||
// TODO: flags for config file (mirrors.json), defaults to mirrors.json
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "path to config file",
|
||||
Destination: &configPath,
|
||||
Value: "data/mirrors.json",
|
||||
EnvVars: []string{"MC_CONFIG_FILE"},
|
||||
},
|
||||
},
|
||||
Commands: []*cli.Command{
|
||||
{
|
||||
Name: "daemon",
|
||||
|
@ -45,12 +57,7 @@ func main() {
|
|||
// TODO: enable all projects by default
|
||||
// checkers.LoadDefaultProjects()
|
||||
|
||||
path := getAbsPath("data/mirrors.json")
|
||||
log.Info().Str("path", path).Msg("Loading config file.")
|
||||
err = config.LoadFromFile(path)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to load config file.")
|
||||
}
|
||||
loadConfig()
|
||||
|
||||
return web.StartServer()
|
||||
},
|
||||
|
@ -61,14 +68,22 @@ func main() {
|
|||
Usage: "checks particular mirror (once)",
|
||||
Action: func(cCtx *cli.Context) error {
|
||||
checkers.LoadDefaultProjects()
|
||||
loadConfig()
|
||||
|
||||
// verify all projects are enabled
|
||||
// TODO:
|
||||
// TODO: ???
|
||||
|
||||
// attempt to look up and check all projects
|
||||
for _, arg := range cCtx.Args().Slice() {
|
||||
log.Printf("\nPulling project information for '%s'\n\n", arg)
|
||||
proj, err := checkers.GetProject(arg)
|
||||
projects := cCtx.Args().Slice()
|
||||
if len(projects) == 0 {
|
||||
log.Fatal().Msg("No projects specified.")
|
||||
}
|
||||
|
||||
log.Debug().Msgf("Checking all specified projects.")
|
||||
|
||||
for _, arg := range projects {
|
||||
log.Info().Msgf("Pulling project information for '%s'.", arg)
|
||||
proj, err := checkers.LoadProject(arg)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).
|
||||
Str("project", arg).
|
||||
|
@ -76,7 +91,21 @@ func main() {
|
|||
return err
|
||||
}
|
||||
|
||||
proj.RunChecksAsync()
|
||||
err = proj.RunChecksAsync(func(res checkers.CheckerResult) {
|
||||
if res.Error != nil {
|
||||
log.Error().Err(res.Error).
|
||||
Time("time", res.Time).
|
||||
Msgf("Failed check %s for project %s", res.CheckerName, res.ProjectName)
|
||||
} else {
|
||||
log.Info().
|
||||
Time("time", res.Time).
|
||||
Str("status", string(res.Status)).
|
||||
Msgf("Completed check %s for project %s", res.CheckerName, res.ProjectName)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to check project.")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
Loading…
Reference in New Issue