forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sharedcontextevaluator.go
116 lines (103 loc) · 3.98 KB
/
sharedcontextevaluator.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
package util
import (
"fmt"
"k8s.io/kubernetes/pkg/admission"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/quota"
"k8s.io/kubernetes/pkg/quota/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/sets"
)
// SharedContextEvaluator provides an implementation for quota.Evaluator
type SharedContextEvaluator struct {
*generic.GenericEvaluator
UsageComputerFactory UsageComputerFactory
}
var _ quota.Evaluator = &SharedContextEvaluator{}
// NewSharedContextEvaluator creates an evaluator object that allows to share context while computing usage of
// single namespace. Context is represented by an object returned by usageComputerFactory and is destroyed
// when the namespace is processed.
func NewSharedContextEvaluator(
name string,
groupKind unversioned.GroupKind,
operationResources map[admission.Operation][]kapi.ResourceName,
matchedResourceNames []kapi.ResourceName,
matchesScopeFunc generic.MatchesScopeFunc,
getFuncByNamespace generic.GetFuncByNamespace,
listFuncByNamespace generic.ListFuncByNamespace,
constraintsFunc generic.ConstraintsFunc,
usageComputerFactory UsageComputerFactory,
) quota.Evaluator {
rnSet := sets.String{}
for _, resourceNames := range operationResources {
rnSet.Insert(quota.ToSet(resourceNames).List()...)
}
return &SharedContextEvaluator{
GenericEvaluator: &generic.GenericEvaluator{
Name: name,
InternalGroupKind: groupKind,
InternalOperationResources: operationResources,
MatchedResourceNames: matchedResourceNames,
MatchesScopeFunc: matchesScopeFunc,
GetFuncByNamespace: getFuncByNamespace,
ListFuncByNamespace: listFuncByNamespace,
ConstraintsFunc: constraintsFunc,
UsageFunc: func(object runtime.Object) kapi.ResourceList {
comp := usageComputerFactory()
return comp.Usage(object)
},
},
UsageComputerFactory: usageComputerFactory,
}
}
// UsageComputer knows how to measure usage associated with an object. Its implementation can store arbitrary
// data during `Usage()` run as a context while namespace is being evaluated.
type UsageComputer interface {
Usage(object runtime.Object) kapi.ResourceList
}
// UsageComputerFactory returns a usage computer used during namespace evaluation.
type UsageComputerFactory func() UsageComputer
// Usage evaluates usage of given object.
func (sce *SharedContextEvaluator) Usage(object runtime.Object) kapi.ResourceList {
usageComp := sce.UsageComputerFactory()
return usageComp.Usage(object)
}
// UsageStats calculates latest observed usage stats for all objects. UsageComputerFactory is used to create a
// UsageComputer object whose Usage is called on every object in a namespace.
func (sce *SharedContextEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.UsageStats, error) {
// default each tracked resource to zero
result := quota.UsageStats{Used: kapi.ResourceList{}}
for _, resourceName := range sce.MatchedResourceNames {
result.Used[resourceName] = resource.MustParse("0")
}
list, err := sce.ListFuncByNamespace(options.Namespace, kapi.ListOptions{})
if err != nil {
return result, fmt.Errorf("%s: Failed to list %v: %v", sce.Name, sce.GroupKind(), err)
}
_, err = meta.Accessor(list)
if err != nil {
return result, fmt.Errorf("%s: Unable to understand list result %#v", sce.Name, list)
}
items, err := meta.ExtractList(list)
if err != nil {
return result, fmt.Errorf("%s: Unable to understand list result %#v (%v)", sce.Name, list, err)
}
context := sce.UsageComputerFactory()
for _, item := range items {
// need to verify that the item matches the set of scopes
matchesScopes := true
for _, scope := range options.Scopes {
if !sce.MatchesScope(scope, item) {
matchesScopes = false
}
}
// only count usage if there was a match
if matchesScopes {
result.Used = quota.Add(result.Used, context.Usage(item))
}
}
return result, nil
}