/
filter.go
124 lines (101 loc) · 3.26 KB
/
filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package k8s
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
)
// ResourceFilter holds resource filtering rules.
type ResourceFilter struct {
watchedNamespaces []string
ignoredNamespaces []string
ignoredServices []namespaceName
ignoredApps []string
}
type namespaceName struct {
Name string
Namespace string
}
// ResourceFilterOption adds a filtering rule to the given ResourceFilter.
type ResourceFilterOption func(filter *ResourceFilter)
// WatchNamespaces add the given namespaces to the list of namespaces to watch.
func WatchNamespaces(namespaces ...string) ResourceFilterOption {
return func(filter *ResourceFilter) {
filter.watchedNamespaces = append(filter.watchedNamespaces, namespaces...)
}
}
// IgnoreNamespaces adds the given namespaces to the list of namespaces to ignore.
func IgnoreNamespaces(namespaces ...string) ResourceFilterOption {
return func(filter *ResourceFilter) {
filter.ignoredNamespaces = append(filter.ignoredNamespaces, namespaces...)
}
}
// IgnoreApps add the given apps to the list of apps to ignore. An app is a Kubernetes object
// with an "app" label, the name of the app being the value of the label.
func IgnoreApps(apps ...string) ResourceFilterOption {
return func(filter *ResourceFilter) {
filter.ignoredApps = append(filter.ignoredApps, apps...)
}
}
// IgnoreService adds the service to the list of service to ignore.
func IgnoreService(namespace, name string) ResourceFilterOption {
return func(filter *ResourceFilter) {
filter.ignoredServices = append(filter.ignoredServices, namespaceName{
Namespace: namespace,
Name: name,
})
}
}
// NewResourceFilter creates a new ResourceFilter, configured with the given options.
func NewResourceFilter(opts ...ResourceFilterOption) *ResourceFilter {
filter := &ResourceFilter{}
for _, opt := range opts {
opt(filter)
}
return filter
}
// IsIgnored returns true if the resource should be ignored.
func (f *ResourceFilter) IsIgnored(obj interface{}) bool {
accessor, err := meta.Accessor(obj)
if err != nil {
return true
}
pMeta := meta.AsPartialObjectMetadata(accessor)
// If we are not watching all namespaces, check if the namespace is in the watch list.
if len(f.watchedNamespaces) > 0 && !contains(f.watchedNamespaces, pMeta.Namespace) {
return true
}
// Check if the namespace is not explicitly ignored.
if contains(f.ignoredNamespaces, pMeta.Namespace) {
return true
}
// Check if the "app" label doesn't contain a value which is ignored.
if contains(f.ignoredApps, pMeta.Labels["app"]) {
return true
}
if svc, ok := obj.(*corev1.Service); ok {
// Check if the service is not explicitly ignored.
if containsNamespaceName(f.ignoredServices, namespaceName{Namespace: svc.Namespace, Name: svc.Name}) {
return true
}
// Ignore ExternalName services as they are not currently supported.
if svc.Spec.Type == corev1.ServiceTypeExternalName {
return true
}
}
return false
}
func contains(slice []string, str string) bool {
for _, item := range slice {
if item == str {
return true
}
}
return false
}
func containsNamespaceName(slice []namespaceName, nn namespaceName) bool {
for _, item := range slice {
if item.Namespace == nn.Namespace && item.Name == nn.Name {
return true
}
}
return false
}