Add flag namspace

wwarren/update-k8s-deps
valbeat 2020-01-09 20:47:38 +09:00
parent 4db75f7c7f
commit 6ef333871c
6 changed files with 363 additions and 3 deletions

View File

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

View File

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

View File

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

28
kube/helper.go Normal file
View File

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

197
kube/objects_filter.go Normal file
View File

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

120
kube/objects_filter_test.go Normal file
View File

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