Use check filter to store groups and checks to run/ignore

varsha/versions
Varsha Varadarajan 2019-06-28 13:40:52 -04:00
parent 4dbcbefec6
commit 4fdebb22d3
3 changed files with 191 additions and 177 deletions

81
checks/check_filter.go Normal file
View File

@ -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
}

View File

@ -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
}

View File

@ -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
}