Merge pull request #4 from digitalocean/varsha/run-checks
Add run command to run all checksvarsha/versions
commit
b7196f4964
|
@ -84,3 +84,12 @@ func GetGroup(name string) []Check {
|
|||
|
||||
return ret
|
||||
}
|
||||
|
||||
func Get(name string) (Check, error) {
|
||||
registry.mu.RLock()
|
||||
defer registry.mu.RUnlock()
|
||||
if registry.checks[name] != nil {
|
||||
return registry.checks[name], nil
|
||||
}
|
||||
return nil, fmt.Errorf("Check not found: %s", name)
|
||||
}
|
||||
|
|
|
@ -3,13 +3,16 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/digitalocean/clusterlint"
|
||||
"github.com/digitalocean/clusterlint/checks"
|
||||
_ "github.com/digitalocean/clusterlint/checks/noop"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sync/errgroup"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
@ -46,27 +49,117 @@ func main() {
|
|||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "run",
|
||||
Usage: "run all checks in the registry",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "group, g",
|
||||
Usage: "run all checks in group `GROUP`",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name, n",
|
||||
Usage: "run a specific check",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
group := c.String("group")
|
||||
name := c.String("name")
|
||||
runChecks(group, name)
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
err := app.Run(os.Args)
|
||||
if err != nil {
|
||||
panic("boo")
|
||||
}
|
||||
// api := &KubernetesAPI{Client: buildClient()}
|
||||
// api.fetch()
|
||||
}
|
||||
|
||||
// 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(group string) {
|
||||
var allChecks []checks.Check
|
||||
if group == "" {
|
||||
allChecks = checks.List()
|
||||
} else {
|
||||
allChecks = checks.GetGroup(group)
|
||||
}
|
||||
allChecks := getChecks(group)
|
||||
for _, check := range allChecks {
|
||||
fmt.Printf("%s : %s\n", check.Name(), check.Description())
|
||||
}
|
||||
}
|
||||
|
||||
func runChecks(group, name string) {
|
||||
api := &KubernetesAPI{Client: buildClient()}
|
||||
objects := api.fetch()
|
||||
if "" == name {
|
||||
runChecksForGroup(group, objects)
|
||||
} else {
|
||||
runCheck(name, objects)
|
||||
}
|
||||
}
|
||||
|
||||
// runChecksForGroup runs all checks in the specified group if found
|
||||
// runs all checks in the registry if group is not specified
|
||||
func runChecksForGroup(group string, objects *clusterlint.KubeObjects) {
|
||||
allChecks := getChecks(group)
|
||||
var warnings, errors []error
|
||||
var mu sync.Mutex
|
||||
var g errgroup.Group
|
||||
|
||||
for _, check := range allChecks {
|
||||
check := check
|
||||
g.Go(func() error {
|
||||
log.Println("Running check: ", check.Name())
|
||||
w, e, err := check.Run(objects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mu.Lock()
|
||||
warnings = append(warnings, w...)
|
||||
errors = append(errors, e...)
|
||||
mu.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
err := g.Wait()
|
||||
showErrorsAndWarnings(warnings, errors)
|
||||
if err != nil {
|
||||
handleError(err)
|
||||
}
|
||||
}
|
||||
|
||||
// runCheck runs a specific check identified by check.Name()
|
||||
// errors out if the check is not found in the registry
|
||||
func runCheck(name string, objects *clusterlint.KubeObjects) {
|
||||
check, err := checks.Get(name)
|
||||
if err != nil {
|
||||
handleError(err)
|
||||
}
|
||||
|
||||
log.Println("Running check: ", name)
|
||||
warnings, errors, err := check.Run(objects)
|
||||
showErrorsAndWarnings(warnings, errors)
|
||||
handleError(err)
|
||||
}
|
||||
|
||||
//showErrorsAndWarnings displays all the errors and warnings returned by checks
|
||||
func showErrorsAndWarnings(warnings, errors []error) {
|
||||
for _, warning := range warnings {
|
||||
log.Println("Warning: ", warning.Error())
|
||||
}
|
||||
for _, err := range errors {
|
||||
log.Println("Error: ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// getChecks retrieves all checks within given group
|
||||
// returns all checks in the registry if group in unspecified
|
||||
func getChecks(group string) []checks.Check {
|
||||
if group == "" {
|
||||
return checks.List()
|
||||
}
|
||||
return checks.GetGroup(group)
|
||||
}
|
||||
|
||||
// fetch initializes a KubeObjects instance with live cluster objects
|
||||
// Currently limited to core k8s API objects
|
||||
func (k KubernetesAPI) fetch() *clusterlint.KubeObjects {
|
||||
client := k.Client.CoreV1()
|
||||
opts := metav1.ListOptions{}
|
||||
|
@ -112,6 +205,8 @@ func (k KubernetesAPI) fetch() *clusterlint.KubeObjects {
|
|||
return objects
|
||||
}
|
||||
|
||||
// buildClient parses command line args and initializes the k8s client
|
||||
// to invoke APIs
|
||||
func buildClient() kubernetes.Interface {
|
||||
k8sconfig := flag.String("kubeconfig", filepath.Join(os.Getenv("HOME"), ".kube", "config"), "absolute path to the kubeconfig file")
|
||||
context := flag.String("context", "", "context for the kubernetes client. default: current context")
|
||||
|
@ -128,6 +223,7 @@ func buildClient() kubernetes.Interface {
|
|||
return client
|
||||
}
|
||||
|
||||
// buildConfigFromFlags initializes client config with given context
|
||||
func buildConfigFromFlags(context, kubeconfigPath *string) (*rest.Config, error) {
|
||||
return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
|
||||
&clientcmd.ClientConfigLoadingRules{ExplicitPath: *kubeconfigPath},
|
||||
|
@ -136,8 +232,9 @@ func buildConfigFromFlags(context, kubeconfigPath *string) (*rest.Config, error)
|
|||
}).ClientConfig()
|
||||
}
|
||||
|
||||
// handleError logs error to stdout and exits
|
||||
func handleError(err error) {
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.12
|
|||
require (
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/urfave/cli v1.19.1
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
k8s.io/api v0.0.0-20190602125759-c1e9adbde704
|
||||
k8s.io/apimachinery v0.0.0-20190602125621-c0632ccbde11
|
||||
k8s.io/client-go v0.0.0-20190602130007-e65ca70987a6
|
||||
|
|
4
go.sum
4
go.sum
|
@ -42,6 +42,8 @@ github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
|
|||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/urfave/cli v1.19.1 h1:0mKm4ZoB74PxYmZVua162y1dGt1qc10MyymYRBf3lb8=
|
||||
github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774 h1:a4tQYYYuK9QdeO/+kEvNYyuR21S+7ve5EANok6hABhI=
|
||||
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -53,6 +55,8 @@ golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0
|
|||
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
|
@ -0,0 +1,3 @@
|
|||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,22 @@
|
|||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package errgroup provides synchronization, error propagation, and Context
|
||||
// cancelation for groups of goroutines working on subtasks of a common task.
|
||||
package errgroup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A Group is a collection of goroutines working on subtasks that are part of
|
||||
// the same overall task.
|
||||
//
|
||||
// A zero Group is valid and does not cancel on error.
|
||||
type Group struct {
|
||||
cancel func()
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
errOnce sync.Once
|
||||
err error
|
||||
}
|
||||
|
||||
// WithContext returns a new Group and an associated Context derived from ctx.
|
||||
//
|
||||
// The derived Context is canceled the first time a function passed to Go
|
||||
// returns a non-nil error or the first time Wait returns, whichever occurs
|
||||
// first.
|
||||
func WithContext(ctx context.Context) (*Group, context.Context) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Group{cancel: cancel}, ctx
|
||||
}
|
||||
|
||||
// Wait blocks until all function calls from the Go method have returned, then
|
||||
// returns the first non-nil error (if any) from them.
|
||||
func (g *Group) Wait() error {
|
||||
g.wg.Wait()
|
||||
if g.cancel != nil {
|
||||
g.cancel()
|
||||
}
|
||||
return g.err
|
||||
}
|
||||
|
||||
// Go calls the given function in a new goroutine.
|
||||
//
|
||||
// The first call to return a non-nil error cancels the group; its error will be
|
||||
// returned by Wait.
|
||||
func (g *Group) Go(f func() error) {
|
||||
g.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
|
||||
if err := f(); err != nil {
|
||||
g.errOnce.Do(func() {
|
||||
g.err = err
|
||||
if g.cancel != nil {
|
||||
g.cancel()
|
||||
}
|
||||
})
|
||||
}
|
||||
}()
|
||||
}
|
|
@ -31,6 +31,8 @@ github.com/pmezard/go-difflib/difflib
|
|||
github.com/spf13/pflag
|
||||
# github.com/stretchr/testify v1.2.2
|
||||
github.com/stretchr/testify/assert
|
||||
# github.com/urfave/cli v1.19.1
|
||||
github.com/urfave/cli
|
||||
# golang.org/x/crypto v0.0.0-20181025213731-e84da0312774
|
||||
golang.org/x/crypto/ssh/terminal
|
||||
# golang.org/x/net v0.0.0-20190206173232-65e2d4e15006
|
||||
|
@ -43,6 +45,8 @@ golang.org/x/net/context/ctxhttp
|
|||
# golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a
|
||||
golang.org/x/oauth2
|
||||
golang.org/x/oauth2/internal
|
||||
# golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sync/errgroup
|
||||
# golang.org/x/sys v0.0.0-20190312061237-fead79001313
|
||||
golang.org/x/sys/unix
|
||||
golang.org/x/sys/windows
|
||||
|
@ -115,18 +119,18 @@ k8s.io/apimachinery/pkg/labels
|
|||
k8s.io/apimachinery/pkg/selection
|
||||
k8s.io/apimachinery/pkg/util/runtime
|
||||
k8s.io/apimachinery/pkg/watch
|
||||
k8s.io/apimachinery/pkg/api/errors
|
||||
k8s.io/apimachinery/pkg/runtime/serializer/streaming
|
||||
k8s.io/apimachinery/pkg/util/net
|
||||
k8s.io/apimachinery/pkg/util/sets
|
||||
k8s.io/apimachinery/pkg/util/errors
|
||||
k8s.io/apimachinery/pkg/util/validation
|
||||
k8s.io/apimachinery/pkg/conversion/queryparams
|
||||
k8s.io/apimachinery/pkg/util/json
|
||||
k8s.io/apimachinery/pkg/util/naming
|
||||
k8s.io/apimachinery/pkg/util/sets
|
||||
k8s.io/apimachinery/third_party/forked/golang/reflect
|
||||
k8s.io/apimachinery/pkg/util/net
|
||||
k8s.io/apimachinery/pkg/api/errors
|
||||
k8s.io/apimachinery/pkg/runtime/serializer
|
||||
k8s.io/apimachinery/pkg/version
|
||||
k8s.io/apimachinery/pkg/runtime/serializer/streaming
|
||||
k8s.io/apimachinery/pkg/util/clock
|
||||
k8s.io/apimachinery/pkg/util/validation/field
|
||||
k8s.io/apimachinery/pkg/runtime/serializer/json
|
||||
|
@ -142,6 +146,7 @@ k8s.io/apimachinery/pkg/util/mergepatch
|
|||
k8s.io/apimachinery/third_party/forked/golang/json
|
||||
# k8s.io/client-go v0.0.0-20190602130007-e65ca70987a6
|
||||
k8s.io/client-go/kubernetes
|
||||
k8s.io/client-go/rest
|
||||
k8s.io/client-go/tools/clientcmd
|
||||
k8s.io/client-go/discovery
|
||||
k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1
|
||||
|
@ -180,21 +185,25 @@ k8s.io/client-go/kubernetes/typed/settings/v1alpha1
|
|||
k8s.io/client-go/kubernetes/typed/storage/v1
|
||||
k8s.io/client-go/kubernetes/typed/storage/v1alpha1
|
||||
k8s.io/client-go/kubernetes/typed/storage/v1beta1
|
||||
k8s.io/client-go/rest
|
||||
k8s.io/client-go/util/flowcontrol
|
||||
k8s.io/client-go/tools/auth
|
||||
k8s.io/client-go/pkg/version
|
||||
k8s.io/client-go/plugin/pkg/client/auth/exec
|
||||
k8s.io/client-go/rest/watch
|
||||
k8s.io/client-go/tools/clientcmd/api
|
||||
k8s.io/client-go/tools/metrics
|
||||
k8s.io/client-go/transport
|
||||
k8s.io/client-go/util/cert
|
||||
k8s.io/client-go/tools/auth
|
||||
k8s.io/client-go/tools/clientcmd/api/latest
|
||||
k8s.io/client-go/util/homedir
|
||||
k8s.io/client-go/kubernetes/fake
|
||||
k8s.io/client-go/kubernetes/scheme
|
||||
k8s.io/client-go/tools/reference
|
||||
k8s.io/client-go/pkg/version
|
||||
k8s.io/client-go/plugin/pkg/client/auth/exec
|
||||
k8s.io/client-go/rest/watch
|
||||
k8s.io/client-go/tools/metrics
|
||||
k8s.io/client-go/transport
|
||||
k8s.io/client-go/util/cert
|
||||
k8s.io/client-go/pkg/apis/clientauthentication
|
||||
k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1
|
||||
k8s.io/client-go/pkg/apis/clientauthentication/v1beta1
|
||||
k8s.io/client-go/util/connrotation
|
||||
k8s.io/client-go/util/keyutil
|
||||
k8s.io/client-go/tools/clientcmd/api/v1
|
||||
k8s.io/client-go/discovery/fake
|
||||
k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1/fake
|
||||
|
@ -234,11 +243,6 @@ k8s.io/client-go/kubernetes/typed/storage/v1/fake
|
|||
k8s.io/client-go/kubernetes/typed/storage/v1alpha1/fake
|
||||
k8s.io/client-go/kubernetes/typed/storage/v1beta1/fake
|
||||
k8s.io/client-go/testing
|
||||
k8s.io/client-go/pkg/apis/clientauthentication
|
||||
k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1
|
||||
k8s.io/client-go/pkg/apis/clientauthentication/v1beta1
|
||||
k8s.io/client-go/util/connrotation
|
||||
k8s.io/client-go/util/keyutil
|
||||
# k8s.io/klog v0.3.2
|
||||
k8s.io/klog
|
||||
# k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30
|
||||
|
|
Loading…
Reference in New Issue