Use check filter to store groups and checks to run/ignore
parent
4dbcbefec6
commit
4fdebb22d3
|
@ -0,0 +1,81 @@
|
|||
package checks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CheckFilter stores names of checks and groups that needs to be included or excluded while running checks
|
||||
type CheckFilter struct {
|
||||
IncludeGroups []string
|
||||
ExcludeGroups []string
|
||||
IncludeChecks []string
|
||||
ExcludeChecks []string
|
||||
}
|
||||
|
||||
// FilterChecks filters all to return set of checks based on the CheckFilter
|
||||
func (c CheckFilter) FilterChecks() ([]Check, error) {
|
||||
if len(c.IncludeChecks) > 0 && len(c.ExcludeChecks) > 0 {
|
||||
return nil, fmt.Errorf("cannot specify both c and C flags")
|
||||
}
|
||||
|
||||
all, err := c.filterGroups()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ret []Check
|
||||
|
||||
if len(c.IncludeChecks) > 0 {
|
||||
for _, check := range all {
|
||||
if c.contains(c.IncludeChecks, check.Name()) {
|
||||
ret = append(ret, check)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
} else if len(c.ExcludeChecks) > 0 {
|
||||
for _, check := range all {
|
||||
if !c.contains(c.ExcludeChecks, check.Name()) {
|
||||
ret = append(ret, check)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
} else {
|
||||
return all, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c CheckFilter) filterGroups() ([]Check, error) {
|
||||
if len(c.IncludeGroups) > 0 && len(c.ExcludeGroups) > 0 {
|
||||
return nil, fmt.Errorf("cannot specify both g and G flags")
|
||||
}
|
||||
|
||||
if len(c.IncludeGroups) > 0 {
|
||||
return GetGroups(c.IncludeGroups), nil
|
||||
} else if len(c.ExcludeGroups) > 0 {
|
||||
return c.getChecksNotInGroups(c.ExcludeGroups), nil
|
||||
} else {
|
||||
return List(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c CheckFilter) getChecksNotInGroups(groups []string) []Check {
|
||||
allGroups := ListGroups()
|
||||
var ret []Check
|
||||
for _, group := range allGroups {
|
||||
if !c.contains(groups, group) {
|
||||
ret = append(ret, GetGroup(group)...)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c CheckFilter) contains(list []string, name string) bool {
|
||||
for _, l := range list {
|
||||
if l == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
package checks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/digitalocean/clusterlint/kube"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// ListChecks lists the names and desc of all checks in the group if found
|
||||
// lists all checks in the registry if group is not specified
|
||||
func ListChecks(c *cli.Context) error {
|
||||
allChecks, err := filterGroups(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, check := range allChecks {
|
||||
fmt.Printf("%s : %s\n", check.Name(), check.Description())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunChecks runs all the checks based on the flags passed.
|
||||
func RunChecks(c *cli.Context) error {
|
||||
client, err := kube.NewClient(c.GlobalString("kubeconfig"), c.GlobalString("context"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objects, err := client.FetchObjects()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runChecks(objects, c)
|
||||
}
|
||||
|
||||
func runChecks(objects *kube.Objects, c *cli.Context) error {
|
||||
all, err := filterGroups(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
all, err = filterChecks(all, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(all) == 0 {
|
||||
return fmt.Errorf("No checks to run. Are you sure that you provided the right names for groups and checks?")
|
||||
}
|
||||
var diagnostics []Diagnostic
|
||||
var mu sync.Mutex
|
||||
var g errgroup.Group
|
||||
|
||||
for _, check := range all {
|
||||
check := check
|
||||
g.Go(func() error {
|
||||
fmt.Println("Running check: ", check.Name())
|
||||
d, err := check.Run(objects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
diagnostics = append(diagnostics, d...)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err = g.Wait()
|
||||
write(diagnostics, c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func write(diagnostics []Diagnostic, c *cli.Context) error {
|
||||
output := c.String("output")
|
||||
level := Severity(c.String("level"))
|
||||
filtered := filterSeverity(level, diagnostics)
|
||||
switch output {
|
||||
case "json":
|
||||
err := json.NewEncoder(os.Stdout).Encode(filtered)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
for _, diagnostic := range filtered {
|
||||
fmt.Printf("%s\n", diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterSeverity(level Severity, diagnostics []Diagnostic) []Diagnostic {
|
||||
if level == "" {
|
||||
return diagnostics
|
||||
}
|
||||
var filtered []Diagnostic
|
||||
for _, d := range diagnostics {
|
||||
if d.Severity == level {
|
||||
filtered = append(filtered, d)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
func filterGroups(c *cli.Context) ([]Check, error) {
|
||||
whitelist := c.StringSlice("g")
|
||||
blacklist := c.StringSlice("G")
|
||||
if len(whitelist) > 0 && len(blacklist) > 0 {
|
||||
return nil, fmt.Errorf("cannot specify both g and G flags")
|
||||
}
|
||||
|
||||
if len(whitelist) > 0 {
|
||||
return GetGroups(whitelist), nil
|
||||
} else if len(blacklist) > 0 {
|
||||
return getChecksNotInGroups(blacklist), nil
|
||||
} else {
|
||||
return List(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func filterChecks(all []Check, c *cli.Context) ([]Check, error) {
|
||||
whitelist := c.StringSlice("c")
|
||||
blacklist := c.StringSlice("C")
|
||||
|
||||
if len(whitelist) > 0 && len(blacklist) > 0 {
|
||||
return nil, fmt.Errorf("cannot specify both c and C flags")
|
||||
}
|
||||
|
||||
var ret []Check
|
||||
|
||||
if len(whitelist) > 0 {
|
||||
for _, c := range all {
|
||||
if contains(whitelist, c.Name()) {
|
||||
ret = append(ret, c)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
} else if len(blacklist) > 0 {
|
||||
for _, c := range all {
|
||||
if !contains(blacklist, c.Name()) {
|
||||
ret = append(ret, c)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
} else {
|
||||
return all, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getChecksNotInGroups(groups []string) []Check {
|
||||
allGroups := ListGroups()
|
||||
var ret []Check
|
||||
for _, group := range allGroups {
|
||||
if !contains(groups, group) {
|
||||
ret = append(ret, GetGroup(group)...)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func contains(list []string, name string) bool {
|
||||
for _, l := range list {
|
||||
if l == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/digitalocean/clusterlint/checks"
|
||||
"github.com/digitalocean/clusterlint/kube"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
// Side-effect import to get all the checks registered.
|
||||
_ "github.com/digitalocean/clusterlint/checks/all"
|
||||
|
@ -41,7 +45,7 @@ func main() {
|
|||
Usage: "list all checks not in groups `GROUP1, GROUP2`",
|
||||
},
|
||||
},
|
||||
Action: checks.ListChecks,
|
||||
Action: listChecks,
|
||||
},
|
||||
{
|
||||
Name: "run",
|
||||
|
@ -72,7 +76,7 @@ func main() {
|
|||
Usage: "Filter output messages based on severity [error|warning|suggestion]. Default: all",
|
||||
},
|
||||
},
|
||||
Action: checks.RunChecks,
|
||||
Action: runChecks,
|
||||
},
|
||||
}
|
||||
err := app.Run(os.Args)
|
||||
|
@ -81,3 +85,107 @@ func main() {
|
|||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// listChecks lists the names and desc of all checks in the group if found
|
||||
// lists all checks in the registry if group is not specified
|
||||
func listChecks(c *cli.Context) error {
|
||||
filter := checks.CheckFilter{
|
||||
IncludeGroups: c.StringSlice("g"),
|
||||
ExcludeGroups: c.StringSlice("G"),
|
||||
}
|
||||
allChecks, err := filter.FilterChecks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, check := range allChecks {
|
||||
fmt.Printf("%s : %s\n", check.Name(), check.Description())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// runChecks runs all the checks based on the flags passed.
|
||||
func runChecks(c *cli.Context) error {
|
||||
client, err := kube.NewClient(c.GlobalString("kubeconfig"), c.GlobalString("context"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
objects, err := client.FetchObjects()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return run(objects, c)
|
||||
}
|
||||
|
||||
func run(objects *kube.Objects, c *cli.Context) error {
|
||||
filter := checks.CheckFilter{
|
||||
IncludeGroups: c.StringSlice("g"),
|
||||
ExcludeGroups: c.StringSlice("G"),
|
||||
IncludeChecks: c.StringSlice("c"),
|
||||
ExcludeChecks: c.StringSlice("C"),
|
||||
}
|
||||
|
||||
all, err := filter.FilterChecks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(all) == 0 {
|
||||
return fmt.Errorf("No checks to run. Are you sure that you provided the right names for groups and checks?")
|
||||
}
|
||||
var diagnostics []checks.Diagnostic
|
||||
var mu sync.Mutex
|
||||
var g errgroup.Group
|
||||
|
||||
for _, check := range all {
|
||||
check := check
|
||||
g.Go(func() error {
|
||||
fmt.Println("Running check: ", check.Name())
|
||||
d, err := check.Run(objects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
diagnostics = append(diagnostics, d...)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err = g.Wait()
|
||||
write(diagnostics, c)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func write(diagnostics []checks.Diagnostic, c *cli.Context) error {
|
||||
output := c.String("output")
|
||||
level := checks.Severity(c.String("level"))
|
||||
filtered := filterSeverity(level, diagnostics)
|
||||
switch output {
|
||||
case "json":
|
||||
err := json.NewEncoder(os.Stdout).Encode(filtered)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
for _, diagnostic := range filtered {
|
||||
fmt.Printf("%s\n", diagnostic)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func filterSeverity(level checks.Severity, diagnostics []checks.Diagnostic) []checks.Diagnostic {
|
||||
if level == "" {
|
||||
return diagnostics
|
||||
}
|
||||
var ret []checks.Diagnostic
|
||||
for _, d := range diagnostics {
|
||||
if d.Severity == level {
|
||||
ret = append(ret, d)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue