Add flag namspace
parent
4db75f7c7f
commit
6ef333871c
|
@ -27,7 +27,7 @@ import (
|
|||
)
|
||||
|
||||
// Run applies the filters and runs the resultant check list in parallel
|
||||
func Run(ctx context.Context, client *kube.Client, checkFilter CheckFilter, diagnosticFilter DiagnosticFilter) (*CheckResult, error) {
|
||||
func Run(ctx context.Context, client *kube.Client, checkFilter CheckFilter, diagnosticFilter DiagnosticFilter, objectFilter kube.ObjectsFilter) (*CheckResult, error) {
|
||||
objects, err := client.FetchObjects(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -40,6 +40,8 @@ func Run(ctx context.Context, client *kube.Client, checkFilter CheckFilter, diag
|
|||
if len(all) == 0 {
|
||||
return nil, errors.New("No checks to run. Are you sure that you provided the right names for groups and checks?")
|
||||
}
|
||||
objectFilter.Filter(objects)
|
||||
|
||||
var diagnostics []Diagnostic
|
||||
var mu sync.Mutex
|
||||
var g errgroup.Group
|
||||
|
|
|
@ -45,7 +45,7 @@ func TestRun(t *testing.T) {
|
|||
alwaysFailCheck, err := Get("always-fail")
|
||||
assert.NoError(t, err)
|
||||
|
||||
result, err := Run(context.Background(), client, filter, DiagnosticFilter{})
|
||||
result, err := Run(context.Background(), client, filter, DiagnosticFilter{},kube.ObjectsFilter{})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, result.Diagnostics, 1)
|
||||
assert.Equal(t, alwaysFailCheck.Name(), result.Diagnostics[0].Check)
|
||||
|
|
|
@ -96,6 +96,14 @@ func main() {
|
|||
Name: "C, ignore-checks",
|
||||
Usage: "run a specific check",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "n, namespaces",
|
||||
Usage: "run checks in specific namespace",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "N, ignore-namespaces",
|
||||
Usage: "run checks not in specific namespace",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "output, o",
|
||||
Usage: "output format [text|json]. Default: text",
|
||||
|
@ -173,7 +181,12 @@ func runChecks(c *cli.Context) error {
|
|||
|
||||
diagnosticFilter := checks.DiagnosticFilter{Severity: checks.Severity(c.String("level"))}
|
||||
|
||||
output, err := checks.Run(context.Background(), client, filter, diagnosticFilter)
|
||||
objectFilter, err := kube.NewObjectsFilter(c.StringSlice("n"), c.StringSlice("N"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := checks.Run(context.Background(), client, filter, diagnosticFilter, objectFilter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Copyright 2019 DigitalOcean
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import "strings"
|
||||
|
||||
func contains(list []string, name string) bool {
|
||||
for _, l := range list {
|
||||
if strings.TrimSpace(l) == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
Copyright 2019 DigitalOcean
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
// Load client-go authentication plugins
|
||||
"fmt"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
// ObjectsFilter stores names of namespaces that needs to be included or excluded while running checks
|
||||
type ObjectsFilter struct {
|
||||
IncludeNamespaces []string
|
||||
ExcludeNamespaces []string
|
||||
}
|
||||
|
||||
|
||||
// NewObjectsFilter is a constructor to initialize an instance of ObjectsFilter
|
||||
func NewObjectsFilter(includeNamespaces, excludeNamespaces []string) (ObjectsFilter, error) {
|
||||
if len(includeNamespaces) > 0 && len(excludeNamespaces) > 0 {
|
||||
return ObjectsFilter{}, fmt.Errorf("cannot specify both include and exclude namespace conditions")
|
||||
}
|
||||
return ObjectsFilter{
|
||||
IncludeNamespaces: includeNamespaces,
|
||||
ExcludeNamespaces: excludeNamespaces,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FilterChecks filters all to return set of checks based on the ObjectsFilter
|
||||
func (f ObjectsFilter) Filter(objects *Objects) {
|
||||
if len(f.IncludeNamespaces) > 0 {
|
||||
var ps []corev1.Pod
|
||||
for _, p := range objects.Pods.Items {
|
||||
if contains(f.IncludeNamespaces, p.Namespace) {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
objects.Pods.Items = ps
|
||||
|
||||
var pts []corev1.PodTemplate
|
||||
for _, pt := range objects.PodTemplates.Items {
|
||||
if contains(f.IncludeNamespaces, pt.Namespace) {
|
||||
pts = append(pts, pt)
|
||||
}
|
||||
}
|
||||
objects.PodTemplates.Items = pts
|
||||
|
||||
var pvcs []corev1.PersistentVolumeClaim
|
||||
for _, pvc := range objects.PersistentVolumeClaims.Items {
|
||||
if contains(f.IncludeNamespaces, pvc.Namespace) {
|
||||
pvcs = append(pvcs, pvc)
|
||||
}
|
||||
}
|
||||
objects.PersistentVolumeClaims.Items = pvcs
|
||||
|
||||
var cms []corev1.ConfigMap
|
||||
for _, cm := range objects.ConfigMaps.Items {
|
||||
if contains(f.IncludeNamespaces, cm.Namespace) {
|
||||
cms = append(cms, cm)
|
||||
}
|
||||
}
|
||||
objects.ConfigMaps.Items = cms
|
||||
|
||||
var svcs []corev1.Service
|
||||
for _, svc := range objects.Services.Items {
|
||||
if contains(f.IncludeNamespaces, svc.Namespace) {
|
||||
svcs = append(svcs, svc)
|
||||
}
|
||||
}
|
||||
objects.Services.Items = svcs
|
||||
|
||||
var scrts []corev1.Secret
|
||||
for _, scrt := range objects.Secrets.Items {
|
||||
if contains(f.IncludeNamespaces, scrt.Namespace) {
|
||||
scrts = append(scrts, scrt)
|
||||
}
|
||||
}
|
||||
objects.Secrets.Items = scrts
|
||||
|
||||
var sas []corev1.ServiceAccount
|
||||
for _, sa := range objects.ServiceAccounts.Items {
|
||||
if contains(f.IncludeNamespaces, sa.Namespace) {
|
||||
sas = append(sas, sa)
|
||||
}
|
||||
}
|
||||
objects.ServiceAccounts.Items = sas
|
||||
|
||||
var rqs []corev1.ResourceQuota
|
||||
for _, rq := range objects.ResourceQuotas.Items {
|
||||
if contains(f.IncludeNamespaces, rq.Namespace) {
|
||||
rqs = append(rqs, rq)
|
||||
}
|
||||
}
|
||||
objects.ResourceQuotas.Items = rqs
|
||||
|
||||
var lrs []corev1.LimitRange
|
||||
for _, lr := range objects.LimitRanges.Items {
|
||||
if contains(f.IncludeNamespaces, lr.Namespace) {
|
||||
lrs = append(lrs, lr)
|
||||
}
|
||||
}
|
||||
objects.LimitRanges.Items = lrs
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if len(f.ExcludeNamespaces) > 0 {
|
||||
var ps []corev1.Pod
|
||||
for _, p := range objects.Pods.Items {
|
||||
if !contains(f.ExcludeNamespaces, p.Namespace) {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
}
|
||||
objects.Pods.Items = ps
|
||||
|
||||
var pts []corev1.PodTemplate
|
||||
for _, pt := range objects.PodTemplates.Items {
|
||||
if !contains(f.ExcludeNamespaces, pt.Namespace) {
|
||||
pts = append(pts, pt)
|
||||
}
|
||||
}
|
||||
objects.PodTemplates.Items = pts
|
||||
|
||||
var pvcs []corev1.PersistentVolumeClaim
|
||||
for _, pvc := range objects.PersistentVolumeClaims.Items {
|
||||
if !contains(f.ExcludeNamespaces, pvc.Namespace) {
|
||||
pvcs = append(pvcs, pvc)
|
||||
}
|
||||
}
|
||||
objects.PersistentVolumeClaims.Items = pvcs
|
||||
|
||||
var cms []corev1.ConfigMap
|
||||
for _, cm := range objects.ConfigMaps.Items {
|
||||
if !contains(f.ExcludeNamespaces, cm.Namespace) {
|
||||
cms = append(cms, cm)
|
||||
}
|
||||
}
|
||||
objects.ConfigMaps.Items = cms
|
||||
|
||||
var svcs []corev1.Service
|
||||
for _, svc := range objects.Services.Items {
|
||||
if !contains(f.ExcludeNamespaces, svc.Namespace) {
|
||||
svcs = append(svcs, svc)
|
||||
}
|
||||
}
|
||||
objects.Services.Items = svcs
|
||||
|
||||
var scrts []corev1.Secret
|
||||
for _, scrt := range objects.Secrets.Items {
|
||||
if !contains(f.ExcludeNamespaces, scrt.Namespace) {
|
||||
scrts = append(scrts, scrt)
|
||||
}
|
||||
}
|
||||
objects.Secrets.Items = scrts
|
||||
|
||||
var sas []corev1.ServiceAccount
|
||||
for _, sa := range objects.ServiceAccounts.Items {
|
||||
if !contains(f.ExcludeNamespaces, sa.Namespace) {
|
||||
sas = append(sas, sa)
|
||||
}
|
||||
}
|
||||
objects.ServiceAccounts.Items = sas
|
||||
|
||||
var rqs []corev1.ResourceQuota
|
||||
for _, rq := range objects.ResourceQuotas.Items {
|
||||
if !contains(f.ExcludeNamespaces, rq.Namespace) {
|
||||
rqs = append(rqs, rq)
|
||||
}
|
||||
}
|
||||
objects.ResourceQuotas.Items = rqs
|
||||
|
||||
var lrs []corev1.LimitRange
|
||||
for _, lr := range objects.LimitRanges.Items {
|
||||
if !contains(f.ExcludeNamespaces, lr.Namespace) {
|
||||
lrs = append(lrs, lr)
|
||||
}
|
||||
}
|
||||
objects.LimitRanges.Items = lrs
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
Copyright 2019 DigitalOcean
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package kube
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNamespaceError(t *testing.T) {
|
||||
_, err := NewObjectsFilter([]string{"kube-system"}, []string{"kube-system"})
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, fmt.Errorf("cannot specify both include and exclude namespace conditions"), err)
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
filter, err := NewObjectsFilter([]string{"namespace_1"},nil)
|
||||
assert.NoError(t, err)
|
||||
objects := namespaceObjects()
|
||||
filter.Filter(objects)
|
||||
assert.Equal(t, namespace1Objects(), objects)
|
||||
|
||||
filter, err = NewObjectsFilter(nil,[]string{"namespace_2"})
|
||||
assert.NoError(t, err)
|
||||
objects = namespaceObjects()
|
||||
filter.Filter(objects)
|
||||
assert.Equal(t, namespace1Objects(), objects)
|
||||
}
|
||||
|
||||
func objects() *Objects {
|
||||
return &Objects{
|
||||
Pods: &corev1.PodList{},
|
||||
PodTemplates: &corev1.PodTemplateList{},
|
||||
PersistentVolumeClaims: &corev1.PersistentVolumeClaimList{},
|
||||
ConfigMaps: &corev1.ConfigMapList{},
|
||||
Services: &corev1.ServiceList{},
|
||||
Secrets: &corev1.SecretList{},
|
||||
ServiceAccounts: &corev1.ServiceAccountList{},
|
||||
ResourceQuotas: &corev1.ResourceQuotaList{},
|
||||
LimitRanges: &corev1.LimitRangeList{},
|
||||
}
|
||||
}
|
||||
|
||||
func namespaceObjects() *Objects {
|
||||
objs := objects()
|
||||
objs.Pods = &corev1.PodList{Items: []corev1.Pod{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pod_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pod_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.PodTemplates = &corev1.PodTemplateList{Items: []corev1.PodTemplate{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "template_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "template_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.PersistentVolumeClaims = &corev1.PersistentVolumeClaimList{Items: []corev1.PersistentVolumeClaim{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pvc_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pvc_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.ConfigMaps = &corev1.ConfigMapList{Items: []corev1.ConfigMap{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "cm_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "cm_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.Services = &corev1.ServiceList{Items: []corev1.Service{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "svc_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "svc_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.Secrets = &corev1.SecretList{Items: []corev1.Secret{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "secret_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "secret_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
objs.ServiceAccounts = &corev1.ServiceAccountList{Items: []corev1.ServiceAccount{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "sa_1", Namespace: "namespace_1"}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "sa_2", Namespace: "namespace_2"}},
|
||||
}}
|
||||
return objs
|
||||
}
|
||||
|
||||
func namespace1Objects() *Objects {
|
||||
objs := objects()
|
||||
objs.Pods = &corev1.PodList{Items: []corev1.Pod{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pod_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.PodTemplates = &corev1.PodTemplateList{Items: []corev1.PodTemplate{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "template_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.PersistentVolumeClaims = &corev1.PersistentVolumeClaimList{Items: []corev1.PersistentVolumeClaim{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "pvc_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.ConfigMaps = &corev1.ConfigMapList{Items: []corev1.ConfigMap{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "cm_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.Services = &corev1.ServiceList{Items: []corev1.Service{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "svc_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.Secrets = &corev1.SecretList{Items: []corev1.Secret{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "secret_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
objs.ServiceAccounts = &corev1.ServiceAccountList{Items: []corev1.ServiceAccount{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "sa_1", Namespace: "namespace_1"}},
|
||||
}}
|
||||
return objs
|
||||
}
|
Loading…
Reference in New Issue