Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
6f3ac807
Commit
6f3ac807
authored
Aug 22, 2016
by
Hongchao Deng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pass SelectionPredicate instead of Filter to storage layer
parent
234be5a1
Hide whitespace changes
Inline
Side-by-side
Showing
56 changed files
with
377 additions
and
410 deletions
+377
-410
reststorage.go
examples/apiserver/rest/reststorage.go
+2
-2
strategy.go
federation/registry/cluster/strategy.go
+3
-2
resthandler.go
pkg/apiserver/resthandler.go
+1
-1
strategy.go
pkg/registry/apps/petset/strategy.go
+3
-2
strategy.go
pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go
+3
-3
strategy.go
pkg/registry/batch/job/strategy.go
+3
-2
strategy.go
pkg/registry/batch/scheduledjob/strategy.go
+3
-2
etcd.go
pkg/registry/certificates/certificates/etcd/etcd.go
+1
-1
strategy.go
pkg/registry/certificates/certificates/strategy.go
+3
-2
strategy.go
pkg/registry/core/configmap/strategy.go
+3
-2
strategy.go
pkg/registry/core/controller/strategy.go
+3
-2
strategy.go
pkg/registry/core/endpoint/strategy.go
+4
-3
strategy.go
pkg/registry/core/event/strategy.go
+3
-2
strategy.go
pkg/registry/core/limitrange/strategy.go
+3
-3
strategy.go
pkg/registry/core/namespace/strategy.go
+3
-2
strategy.go
pkg/registry/core/node/strategy.go
+2
-2
strategy.go
pkg/registry/core/persistentvolume/strategy.go
+3
-2
strategy.go
pkg/registry/core/persistentvolumeclaim/strategy.go
+3
-2
strategy.go
pkg/registry/core/pod/strategy.go
+2
-2
strategy_test.go
pkg/registry/core/pod/strategy_test.go
+2
-1
strategy.go
pkg/registry/core/podtemplate/strategy.go
+3
-3
strategy.go
pkg/registry/core/resourcequota/strategy.go
+3
-2
strategy.go
pkg/registry/core/secret/strategy.go
+3
-2
strategy.go
pkg/registry/core/service/strategy.go
+3
-2
strategy.go
pkg/registry/core/serviceaccount/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/daemonset/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/deployment/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/ingress/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/networkpolicy/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/podsecuritypolicy/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/replicaset/strategy.go
+3
-2
strategy.go
pkg/registry/extensions/thirdpartyresource/strategy.go
+3
-3
strategy.go
pkg/registry/extensions/thirdpartyresourcedata/strategy.go
+3
-3
matcher.go
pkg/registry/generic/matcher.go
+0
-82
store.go
pkg/registry/generic/registry/store.go
+10
-26
store_test.go
pkg/registry/generic/registry/store_test.go
+8
-8
strategy.go
pkg/registry/policy/poddisruptionbudget/strategy.go
+3
-2
strategy.go
pkg/registry/rbac/clusterrole/strategy.go
+3
-3
strategy.go
pkg/registry/rbac/clusterrolebinding/strategy.go
+3
-3
strategy.go
pkg/registry/rbac/role/strategy.go
+3
-3
strategy.go
pkg/registry/rbac/rolebinding/strategy.go
+3
-3
strategy.go
pkg/registry/storage/storageclass/strategy.go
+3
-2
cacher.go
pkg/storage/cacher.go
+21
-20
cacher_test.go
pkg/storage/cacher_test.go
+15
-13
etcd_helper.go
pkg/storage/etcd/etcd_helper.go
+13
-13
etcd_helper_test.go
pkg/storage/etcd/etcd_helper_test.go
+11
-6
etcd_watcher.go
pkg/storage/etcd/etcd_watcher.go
+7
-7
etcd_watcher_test.go
pkg/storage/etcd/etcd_watcher_test.go
+9
-20
store.go
pkg/storage/etcd3/store.go
+11
-11
store_test.go
pkg/storage/etcd3/store_test.go
+27
-34
watcher.go
pkg/storage/etcd3/watcher.go
+7
-7
watcher_test.go
pkg/storage/etcd3/watcher_test.go
+22
-23
interfaces.go
pkg/storage/interfaces.go
+15
-33
selection_predicate.go
pkg/storage/selection_predicate.go
+77
-0
selection_predicate_test.go
pkg/storage/selection_predicate_test.go
+2
-2
util.go
pkg/storage/util.go
+12
-20
No files found.
examples/apiserver/rest/reststorage.go
View file @
6f3ac807
...
...
@@ -61,8 +61,8 @@ func NewREST(config *storagebackend.Config, storageDecorator generic.StorageDeco
return
obj
.
(
*
testgroup
.
TestType
)
.
Name
,
nil
},
// Used to match objects based on labels/fields for list.
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
federation/registry/cluster/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -44,8 +45,8 @@ func ClusterToSelectableFields(cluster *federation.Cluster) fields.Set {
return
generic
.
ObjectMetaFieldsSet
(
&
cluster
.
ObjectMeta
,
false
)
}
func
MatchCluster
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchCluster
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/apiserver/resthandler.go
View file @
6f3ac807
...
...
@@ -277,7 +277,7 @@ func ListResource(r rest.Lister, rw rest.Watcher, scope RequestScope, forceWatch
if
hasName
{
// metadata.name is the canonical internal name.
//
generic.
SelectionPredicate will notice that this is
// SelectionPredicate will notice that this is
// a request for a single object and optimize the
// storage query accordingly.
nameSelector
:=
fields
.
OneTermEqualSelector
(
"metadata.name"
,
name
)
...
...
pkg/registry/apps/petset/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -103,8 +104,8 @@ func PetSetToSelectableFields(petSet *apps.PetSet) fields.Set {
// MatchPetSet is the filter used by the generic etcd backend to watch events
// from etcd to clients of the apiserver only interested in specific labels/fields.
func
MatchPetSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPetSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go
View file @
6f3ac807
...
...
@@ -24,8 +24,8 @@ import (
"k8s.io/kubernetes/pkg/apis/autoscaling/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -88,8 +88,8 @@ func AutoscalerToSelectableFields(hpa *autoscaling.HorizontalPodAutoscaler) fiel
return
nil
}
func
MatchAutoscaler
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchAutoscaler
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/batch/job/strategy.go
View file @
6f3ac807
...
...
@@ -28,6 +28,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -166,8 +167,8 @@ func JobToSelectableFields(job *batch.Job) fields.Set {
// MatchJob is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchJob
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchJob
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/batch/scheduledjob/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -104,8 +105,8 @@ func ScheduledJobToSelectableFields(scheduledJob *batch.ScheduledJob) fields.Set
// MatchScheduledJob is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchScheduledJob
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchScheduledJob
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/certificates/certificates/etcd/etcd.go
View file @
6f3ac807
...
...
@@ -62,7 +62,7 @@ func NewREST(opts generic.RESTOptions) (*REST, *StatusREST, *ApprovalREST) {
ObjectNameFunc
:
func
(
obj
runtime
.
Object
)
(
string
,
error
)
{
return
obj
.
(
*
certificates
.
CertificateSigningRequest
)
.
Name
,
nil
},
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
csrregistry
.
Matcher
(
label
,
field
)
},
QualifiedResource
:
certificates
.
Resource
(
"certificatesigningrequests"
),
...
...
pkg/registry/certificates/certificates/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -168,8 +169,8 @@ func (csrApprovalStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Obje
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/configmap/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -88,8 +89,8 @@ func ConfigMapToSelectableFields(cfg *api.ConfigMap) fields.Set {
}
// MatchConfigMap returns a generic matcher for a given label and field selector.
func
MatchConfigMap
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchConfigMap
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/controller/strategy.go
View file @
6f3ac807
...
...
@@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -120,8 +121,8 @@ func ControllerToSelectableFields(controller *api.ReplicationController) fields.
// MatchController is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchController
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchController
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/endpoint/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -79,12 +80,12 @@ func (endpointsStrategy) AllowUnconditionalUpdate() bool {
}
// MatchEndpoints returns a generic matcher for a given label and field selector.
func
MatchEndpoints
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
EndpointsAttributes
}
func
MatchEndpoints
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
EndpointsAttributes
}
}
// EndpointsAttributes returns the attributes of an endpoint such that a
//
generic.
SelectionPredicate can match appropriately.
// SelectionPredicate can match appropriately.
func
EndpointsAttributes
(
obj
runtime
.
Object
)
(
objLabels
labels
.
Set
,
objFields
fields
.
Set
,
err
error
)
{
endpoints
,
ok
:=
obj
.
(
*
api
.
Endpoints
)
if
!
ok
{
...
...
pkg/registry/core/event/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -69,8 +70,8 @@ func (eventStrategy) AllowUnconditionalUpdate() bool {
return
true
}
func
MatchEvent
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchEvent
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/limitrange/strategy.go
View file @
6f3ac807
...
...
@@ -23,8 +23,8 @@ import (
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/uuid"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -85,8 +85,8 @@ func (limitrangeStrategy) Export(api.Context, runtime.Object, bool) error {
return
nil
}
func
MatchLimitRange
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchLimitRange
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/namespace/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -135,8 +136,8 @@ func (namespaceFinalizeStrategy) PrepareForUpdate(ctx api.Context, obj, old runt
}
// MatchNamespace returns a generic matcher for a given label and field selector.
func
MatchNamespace
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchNamespace
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/node/strategy.go
View file @
6f3ac807
...
...
@@ -147,8 +147,8 @@ func NodeToSelectableFields(node *api.Node) fields.Set {
}
// MatchNode returns a generic matcher for a given label and field selector.
func
MatchNode
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchNode
(
label
labels
.
Selector
,
field
fields
.
Selector
)
pkgstorage
.
SelectionPredicate
{
return
pkgstorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/persistentvolume/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -95,8 +96,8 @@ func (persistentvolumeStatusStrategy) ValidateUpdate(ctx api.Context, obj, old r
}
// MatchPersistentVolume returns a generic matcher for a given label and field selector.
func
MatchPersistentVolumes
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPersistentVolumes
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/persistentvolumeclaim/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -95,8 +96,8 @@ func (persistentvolumeclaimStatusStrategy) ValidateUpdate(ctx api.Context, obj,
}
// MatchPersistentVolumeClaim returns a generic matcher for a given label and field selector.
func
MatchPersistentVolumeClaim
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPersistentVolumeClaim
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/pod/strategy.go
View file @
6f3ac807
...
...
@@ -155,8 +155,8 @@ func (podStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object
}
// MatchPod returns a generic matcher for a given label and field selector.
func
MatchPod
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPod
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/pod/strategy_test.go
View file @
6f3ac807
...
...
@@ -79,7 +79,8 @@ func TestMatchPod(t *testing.T) {
},
}
for
_
,
testCase
:=
range
testCases
{
result
,
err
:=
MatchPod
(
labels
.
Everything
(),
testCase
.
fieldSelector
)
.
Matches
(
testCase
.
in
)
m
:=
MatchPod
(
labels
.
Everything
(),
testCase
.
fieldSelector
)
result
,
err
:=
m
.
Matches
(
testCase
.
in
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v"
,
err
)
}
...
...
pkg/registry/core/podtemplate/strategy.go
View file @
6f3ac807
...
...
@@ -23,8 +23,8 @@ import (
"k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -86,8 +86,8 @@ func PodTemplateToSelectableFields(podTemplate *api.PodTemplate) fields.Set {
return
nil
}
func
MatchPodTemplate
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPodTemplate
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/resourcequota/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -98,8 +99,8 @@ func (resourcequotaStatusStrategy) ValidateUpdate(ctx api.Context, obj, old runt
}
// MatchResourceQuota returns a generic matcher for a given label and field selector.
func
MatchResourceQuota
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchResourceQuota
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/secret/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -94,8 +95,8 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/service/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -100,8 +101,8 @@ func (svcStrategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
return
nil
}
func
MatchServices
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchServices
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/core/serviceaccount/strategy.go
View file @
6f3ac807
...
...
@@ -25,6 +25,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -77,8 +78,8 @@ func (strategy) AllowUnconditionalUpdate() bool {
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/daemonset/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -112,8 +113,8 @@ func DaemonSetToSelectableFields(daemon *extensions.DaemonSet) fields.Set {
// MatchSetDaemon is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchDaemonSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchDaemonSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/deployment/strategy.go
View file @
6f3ac807
...
...
@@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -130,8 +131,8 @@ func DeploymentToSelectableFields(deployment *extensions.Deployment) fields.Set
// MatchDeployment is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchDeployment
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchDeployment
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/ingress/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -105,8 +106,8 @@ func IngressToSelectableFields(ingress *extensions.Ingress) fields.Set {
// MatchIngress is the filter used by the generic etcd backend to ingress
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchIngress
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchIngress
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/networkpolicy/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -97,8 +98,8 @@ func NetworkPolicyToSelectableFields(networkPolicy *extensions.NetworkPolicy) fi
// MatchNetworkPolicy is the filter used by the generic etcd backend to watch events
// from etcd to clients of the apiserver only interested in specific labels/fields.
func
MatchNetworkPolicy
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchNetworkPolicy
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/podsecuritypolicy/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -74,8 +75,8 @@ func (strategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.E
}
// Matcher returns a generic matcher for a given label and field selector.
func
MatchPodSecurityPolicy
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPodSecurityPolicy
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/replicaset/strategy.go
View file @
6f3ac807
...
...
@@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -121,8 +122,8 @@ func ReplicaSetToSelectableFields(rs *extensions.ReplicaSet) fields.Set {
// MatchReplicaSet is the filter used by the generic etcd backend to route
// watch events from etcd to clients of the apiserver only interested in specific
// labels/fields.
func
MatchReplicaSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchReplicaSet
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/thirdpartyresource/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -78,8 +78,8 @@ func (strategy) AllowUnconditionalUpdate() bool {
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/extensions/thirdpartyresourcedata/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/extensions/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -75,8 +75,8 @@ func (strategy) AllowUnconditionalUpdate() bool {
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/generic/matcher.go
View file @
6f3ac807
...
...
@@ -19,14 +19,8 @@ package generic
import
(
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
)
// AttrFunc returns label and field sets for List or Watch to compare against, or an error.
type
AttrFunc
func
(
obj
runtime
.
Object
)
(
label
labels
.
Set
,
field
fields
.
Set
,
err
error
)
// ObjectMetaFieldsSet returns a fields that represents the ObjectMeta.
func
ObjectMetaFieldsSet
(
objectMeta
*
api
.
ObjectMeta
,
hasNamespaceField
bool
)
fields
.
Set
{
if
!
hasNamespaceField
{
...
...
@@ -47,79 +41,3 @@ func MergeFieldsSets(source fields.Set, fragment fields.Set) fields.Set {
}
return
source
}
// SelectionPredicate implements a generic predicate that can be passed to
// GenericRegistry's List or Watch methods. Implements the Matcher interface.
type
SelectionPredicate
struct
{
Label
labels
.
Selector
Field
fields
.
Selector
GetAttrs
AttrFunc
IndexFields
[]
string
}
// Matches returns true if the given object's labels and fields (as
// returned by s.GetAttrs) match s.Label and s.Field. An error is
// returned if s.GetAttrs fails.
func
(
s
*
SelectionPredicate
)
Matches
(
obj
runtime
.
Object
)
(
bool
,
error
)
{
if
s
.
Label
.
Empty
()
&&
s
.
Field
.
Empty
()
{
return
true
,
nil
}
labels
,
fields
,
err
:=
s
.
GetAttrs
(
obj
)
if
err
!=
nil
{
return
false
,
err
}
matched
:=
s
.
Label
.
Matches
(
labels
)
if
s
.
Field
!=
nil
{
matched
=
(
matched
&&
s
.
Field
.
Matches
(
fields
))
}
return
matched
,
nil
}
// MatchesSingle will return (name, true) if and only if s.Field matches on the object's
// name.
func
(
s
*
SelectionPredicate
)
MatchesSingle
()
(
string
,
bool
)
{
// TODO: should be namespace.name
if
name
,
ok
:=
s
.
Field
.
RequiresExactMatch
(
"metadata.name"
);
ok
{
return
name
,
true
}
return
""
,
false
}
// For any index defined by IndexFields, if a matcher can match only (a subset)
// of objects that return <value> for a given index, a pair (<index name>, <value>)
// wil be returned.
// TODO: Consider supporting also labels.
func
(
s
*
SelectionPredicate
)
MatcherIndex
()
[]
storage
.
MatchValue
{
var
result
[]
storage
.
MatchValue
for
_
,
field
:=
range
s
.
IndexFields
{
if
value
,
ok
:=
s
.
Field
.
RequiresExactMatch
(
field
);
ok
{
result
=
append
(
result
,
storage
.
MatchValue
{
IndexName
:
field
,
Value
:
value
})
}
}
return
result
}
// Matcher can return true if an object matches the Matcher's selection
// criteria. If it is known that the matcher will match only a single object
// then MatchesSingle should return the key of that object and true. This is an
// optimization only--Matches() should continue to work.
type
Matcher
interface
{
// Matches should return true if obj matches this matcher's requirements.
Matches
(
obj
runtime
.
Object
)
(
matchesThisObject
bool
,
err
error
)
// If this matcher matches a single object, return the key for that
// object and true here. This will greatly increase efficiency. You
// must still implement Matches(). Note that key does NOT need to
// include the object's namespace.
MatchesSingle
()
(
key
string
,
matchesSingleObject
bool
)
// For any known index, if a matcher can match only (a subset) of objects
// that return <value> for a given index, a pair (<index name>, <value>)
// will be returned.
MatcherIndex
()
[]
storage
.
MatchValue
}
var
(
// Assert implementations match the interface.
_
=
Matcher
(
&
SelectionPredicate
{})
)
pkg/registry/generic/registry/store.go
View file @
6f3ac807
...
...
@@ -32,7 +32,6 @@ import (
"k8s.io/kubernetes/pkg/api/validation/path"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
utilruntime
"k8s.io/kubernetes/pkg/util/runtime"
...
...
@@ -85,7 +84,7 @@ type Store struct {
TTLFunc
func
(
obj
runtime
.
Object
,
existing
uint64
,
update
bool
)
(
uint64
,
error
)
// Returns a matcher corresponding to the provided labels and fields.
PredicateFunc
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
PredicateFunc
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
// Called to cleanup storage clients.
DestroyFunc
func
()
...
...
@@ -201,12 +200,11 @@ func (e *Store) List(ctx api.Context, options *api.ListOptions) (runtime.Object,
}
// ListPredicate returns a list of all the items matching m.
func
(
e
*
Store
)
ListPredicate
(
ctx
api
.
Context
,
m
*
generic
.
SelectionPredicate
,
options
*
api
.
ListOptions
)
(
runtime
.
Object
,
error
)
{
func
(
e
*
Store
)
ListPredicate
(
ctx
api
.
Context
,
p
storage
.
SelectionPredicate
,
options
*
api
.
ListOptions
)
(
runtime
.
Object
,
error
)
{
list
:=
e
.
NewListFunc
()
filter
:=
e
.
createFilter
(
m
)
if
name
,
ok
:=
m
.
MatchesSingle
();
ok
{
if
name
,
ok
:=
p
.
MatchesSingle
();
ok
{
if
key
,
err
:=
e
.
KeyFunc
(
ctx
,
name
);
err
==
nil
{
err
:=
e
.
Storage
.
GetToList
(
ctx
,
key
,
filter
,
list
)
err
:=
e
.
Storage
.
GetToList
(
ctx
,
key
,
p
,
list
)
return
list
,
storeerr
.
InterpretListError
(
err
,
e
.
QualifiedResource
)
}
// if we cannot extract a key based on the current context, the optimization is skipped
...
...
@@ -215,7 +213,7 @@ func (e *Store) ListPredicate(ctx api.Context, m *generic.SelectionPredicate, op
if
options
==
nil
{
options
=
&
api
.
ListOptions
{
ResourceVersion
:
"0"
}
}
err
:=
e
.
Storage
.
List
(
ctx
,
e
.
KeyRootFunc
(
ctx
),
options
.
ResourceVersion
,
filter
,
list
)
err
:=
e
.
Storage
.
List
(
ctx
,
e
.
KeyRootFunc
(
ctx
),
options
.
ResourceVersion
,
p
,
list
)
return
list
,
storeerr
.
InterpretListError
(
err
,
e
.
QualifiedResource
)
}
...
...
@@ -853,7 +851,7 @@ func (e *Store) finalizeDelete(obj runtime.Object, runHooks bool) (runtime.Objec
// Watch makes a matcher for the given label and field, and calls
// WatchPredicate. If possible, you should customize PredicateFunc to produre a
// matcher that matches by key.
generic.
SelectionPredicate does this for you
// matcher that matches by key. SelectionPredicate does this for you
// automatically.
func
(
e
*
Store
)
Watch
(
ctx
api
.
Context
,
options
*
api
.
ListOptions
)
(
watch
.
Interface
,
error
)
{
label
:=
labels
.
Everything
()
...
...
@@ -872,15 +870,13 @@ func (e *Store) Watch(ctx api.Context, options *api.ListOptions) (watch.Interfac
}
// WatchPredicate starts a watch for the items that m matches.
func
(
e
*
Store
)
WatchPredicate
(
ctx
api
.
Context
,
m
*
generic
.
SelectionPredicate
,
resourceVersion
string
)
(
watch
.
Interface
,
error
)
{
filter
:=
e
.
createFilter
(
m
)
if
name
,
ok
:=
m
.
MatchesSingle
();
ok
{
func
(
e
*
Store
)
WatchPredicate
(
ctx
api
.
Context
,
p
storage
.
SelectionPredicate
,
resourceVersion
string
)
(
watch
.
Interface
,
error
)
{
if
name
,
ok
:=
p
.
MatchesSingle
();
ok
{
if
key
,
err
:=
e
.
KeyFunc
(
ctx
,
name
);
err
==
nil
{
if
err
!=
nil
{
return
nil
,
err
}
w
,
err
:=
e
.
Storage
.
Watch
(
ctx
,
key
,
resourceVersion
,
filter
)
w
,
err
:=
e
.
Storage
.
Watch
(
ctx
,
key
,
resourceVersion
,
p
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -892,7 +888,7 @@ func (e *Store) WatchPredicate(ctx api.Context, m *generic.SelectionPredicate, r
// if we cannot extract a key based on the current context, the optimization is skipped
}
w
,
err
:=
e
.
Storage
.
WatchList
(
ctx
,
e
.
KeyRootFunc
(
ctx
),
resourceVersion
,
filter
)
w
,
err
:=
e
.
Storage
.
WatchList
(
ctx
,
e
.
KeyRootFunc
(
ctx
),
resourceVersion
,
p
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -902,18 +898,6 @@ func (e *Store) WatchPredicate(ctx api.Context, m *generic.SelectionPredicate, r
return
w
,
nil
}
func
(
e
*
Store
)
createFilter
(
m
*
generic
.
SelectionPredicate
)
storage
.
Filter
{
filterFunc
:=
func
(
obj
runtime
.
Object
)
bool
{
matches
,
err
:=
m
.
Matches
(
obj
)
if
err
!=
nil
{
glog
.
Errorf
(
"unable to match watch: %v"
,
err
)
return
false
}
return
matches
}
return
storage
.
NewSimpleFilter
(
filterFunc
,
m
.
MatcherIndex
)
}
// calculateTTL is a helper for retrieving the updated TTL for an object or returning an error
// if the TTL cannot be calculated. The defaultTTL is changed to 1 if less than zero. Zero means
// no TTL, not expire immediately.
...
...
pkg/registry/generic/registry/store_test.go
View file @
6f3ac807
...
...
@@ -106,14 +106,14 @@ func NewTestGenericStoreRegistry(t *testing.T) (factory.DestroyFunc, *Store) {
// matchPodName returns selection predicate that matches any pod with name in the set.
// Makes testing simpler.
func
matchPodName
(
names
...
string
)
*
generic
.
SelectionPredicate
{
func
matchPodName
(
names
...
string
)
storage
.
SelectionPredicate
{
// Note: even if pod name is a field, we have to use labels,
// because field selector doesn't support "IN" operator.
l
,
err
:=
labels
.
NewRequirement
(
"name"
,
selection
.
In
,
sets
.
NewString
(
names
...
))
if
err
!=
nil
{
panic
(
"Labels requirement must validate successfully"
)
}
return
&
generic
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
()
.
Add
(
*
l
),
Field
:
fields
.
Everything
(),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
label
labels
.
Set
,
field
fields
.
Set
,
err
error
)
{
...
...
@@ -123,8 +123,8 @@ func matchPodName(names ...string) *generic.SelectionPredicate {
}
}
func
matchEverything
()
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
matchEverything
()
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
Everything
(),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
label
labels
.
Set
,
field
fields
.
Set
,
err
error
)
{
...
...
@@ -148,7 +148,7 @@ func TestStoreList(t *testing.T) {
table
:=
map
[
string
]
struct
{
in
*
api
.
PodList
m
*
generic
.
SelectionPredicate
m
storage
.
SelectionPredicate
out
runtime
.
Object
context
api
.
Context
}{
...
...
@@ -1141,7 +1141,7 @@ func TestStoreWatch(t *testing.T) {
noNamespaceContext
:=
api
.
NewContext
()
table
:=
map
[
string
]
struct
{
selectPred
*
generic
.
SelectionPredicate
selectPred
storage
.
SelectionPredicate
context
api
.
Context
}{
"single"
:
{
...
...
@@ -1242,8 +1242,8 @@ func newTestGenericStoreRegistry(t *testing.T, hasCacheEnabled bool) (factory.De
return
path
.
Join
(
podPrefix
,
id
),
nil
},
ObjectNameFunc
:
func
(
obj
runtime
.
Object
)
(
string
,
error
)
{
return
obj
.
(
*
api
.
Pod
)
.
Name
,
nil
},
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
PredicateFunc
:
func
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/policy/poddisruptionbudget/strategy.go
View file @
6f3ac807
...
...
@@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -102,8 +103,8 @@ func PodDisruptionBudgetToSelectableFields(podDisruptionBudget *policy.PodDisrup
// MatchPodDisruptionBudget is the filter used by the generic etcd backend to watch events
// from etcd to clients of the apiserver only interested in specific labels/fields.
func
MatchPodDisruptionBudget
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchPodDisruptionBudget
(
label
labels
.
Selector
,
field
fields
.
Selector
)
storage
.
SelectionPredicate
{
return
storage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/rbac/clusterrole/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -102,8 +102,8 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/rbac/clusterrolebinding/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -102,8 +102,8 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/rbac/role/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -102,8 +102,8 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/rbac/rolebinding/strategy.go
View file @
6f3ac807
...
...
@@ -25,8 +25,8 @@ import (
"k8s.io/kubernetes/pkg/apis/rbac/validation"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -102,8 +102,8 @@ func (s strategy) Export(ctx api.Context, obj runtime.Object, exact bool) error
}
// Matcher returns a generic matcher for a given label and field selector.
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
Matcher
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/registry/storage/storageclass/strategy.go
View file @
6f3ac807
...
...
@@ -26,6 +26,7 @@ import (
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime"
apistorage
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/validation/field"
)
...
...
@@ -77,8 +78,8 @@ func (storageClassStrategy) AllowUnconditionalUpdate() bool {
}
// MatchStorageClass returns a generic matcher for a given label and field selector.
func
MatchStorageClasses
(
label
labels
.
Selector
,
field
fields
.
Selector
)
*
generic
.
SelectionPredicate
{
return
&
generic
.
SelectionPredicate
{
func
MatchStorageClasses
(
label
labels
.
Selector
,
field
fields
.
Selector
)
apistorage
.
SelectionPredicate
{
return
apistorage
.
SelectionPredicate
{
Label
:
label
,
Field
:
field
,
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
...
...
pkg/storage/cacher.go
View file @
6f3ac807
...
...
@@ -278,7 +278,7 @@ func (c *Cacher) Delete(ctx context.Context, key string, out runtime.Object, pre
}
// Implements storage.Interface.
func
(
c
*
Cacher
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
)
(
watch
.
Interface
,
error
)
{
func
(
c
*
Cacher
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
watchRV
,
err
:=
ParseWatchResourceVersion
(
resourceVersion
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -302,17 +302,17 @@ func (c *Cacher) Watch(ctx context.Context, key string, resourceVersion string,
}
triggerValue
,
triggerSupported
:=
""
,
false
// TODO: Currently we assume that in a given Cacher object, any <
filter
> that is
// TODO: Currently we assume that in a given Cacher object, any <
predicate
> that is
// passed here is aware of exactly the same trigger (at most one).
// Thus, either 0 or 1 values will be returned.
if
matchValues
:=
filter
.
Trigger
();
len
(
matchValues
)
>
0
{
if
matchValues
:=
pred
.
MatcherIndex
();
len
(
matchValues
)
>
0
{
triggerValue
,
triggerSupported
=
matchValues
[
0
]
.
Value
,
true
}
c
.
Lock
()
defer
c
.
Unlock
()
forget
:=
forgetWatcher
(
c
,
c
.
watcherIdx
,
triggerValue
,
triggerSupported
)
watcher
:=
newCacheWatcher
(
watchRV
,
initEvents
,
filterFunction
(
key
,
c
.
keyFunc
,
filter
),
forget
)
watcher
:=
newCacheWatcher
(
watchRV
,
initEvents
,
filterFunction
(
key
,
c
.
keyFunc
,
pred
),
forget
)
c
.
watchers
.
addWatcher
(
watcher
,
c
.
watcherIdx
,
triggerValue
,
triggerSupported
)
c
.
watcherIdx
++
...
...
@@ -320,8 +320,8 @@ func (c *Cacher) Watch(ctx context.Context, key string, resourceVersion string,
}
// Implements storage.Interface.
func
(
c
*
Cacher
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
)
(
watch
.
Interface
,
error
)
{
return
c
.
Watch
(
ctx
,
key
,
resourceVersion
,
filter
)
func
(
c
*
Cacher
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
return
c
.
Watch
(
ctx
,
key
,
resourceVersion
,
pred
)
}
// Implements storage.Interface.
...
...
@@ -330,16 +330,16 @@ func (c *Cacher) Get(ctx context.Context, key string, objPtr runtime.Object, ign
}
// Implements storage.Interface.
func
(
c
*
Cacher
)
GetToList
(
ctx
context
.
Context
,
key
string
,
filter
Filter
,
listObj
runtime
.
Object
)
error
{
return
c
.
storage
.
GetToList
(
ctx
,
key
,
filter
,
listObj
)
func
(
c
*
Cacher
)
GetToList
(
ctx
context
.
Context
,
key
string
,
pred
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
return
c
.
storage
.
GetToList
(
ctx
,
key
,
pred
,
listObj
)
}
// Implements storage.Interface.
func
(
c
*
Cacher
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
c
*
Cacher
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
if
resourceVersion
==
""
{
// If resourceVersion is not specified, serve it from underlying
// storage (for backward compatibility).
return
c
.
storage
.
List
(
ctx
,
key
,
resourceVersion
,
filter
,
listObj
)
return
c
.
storage
.
List
(
ctx
,
key
,
resourceVersion
,
pred
,
listObj
)
}
// If resourceVersion is specified, serve it from cache.
...
...
@@ -362,7 +362,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, f
if
err
!=
nil
||
listVal
.
Kind
()
!=
reflect
.
Slice
{
return
fmt
.
Errorf
(
"need a pointer to slice, got %v"
,
listVal
.
Kind
())
}
filter
Func
:=
filterFunction
(
key
,
c
.
keyFunc
,
filter
)
filter
:=
filterFunction
(
key
,
c
.
keyFunc
,
pred
)
objs
,
readResourceVersion
,
err
:=
c
.
watchCache
.
WaitUntilFreshAndList
(
listRV
)
if
err
!=
nil
{
...
...
@@ -373,7 +373,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, f
if
!
ok
{
return
fmt
.
Errorf
(
"non runtime.Object returned from storage: %v"
,
obj
)
}
if
filter
Func
.
Filter
(
object
)
{
if
filter
(
object
)
{
listVal
.
Set
(
reflect
.
Append
(
listVal
,
reflect
.
ValueOf
(
object
)
.
Elem
()))
}
}
...
...
@@ -502,19 +502,20 @@ func forgetWatcher(c *Cacher, index int, triggerValue string, triggerSupported b
}
}
func
filterFunction
(
key
string
,
keyFunc
func
(
runtime
.
Object
)
(
string
,
error
),
filter
Filter
)
Filter
{
func
filterFunction
(
key
string
,
keyFunc
func
(
runtime
.
Object
)
(
string
,
error
),
p
SelectionPredicate
)
FilterFunc
{
f
:=
SimpleFilter
(
p
)
filterFunc
:=
func
(
obj
runtime
.
Object
)
bool
{
objKey
,
err
:=
keyFunc
(
obj
)
if
err
!=
nil
{
glog
.
Errorf
(
"invalid object for filter
: %v"
,
obj
)
glog
.
Errorf
(
"invalid object for filter
. Obj: %v. Err: %v"
,
obj
,
err
)
return
false
}
if
!
hasPathPrefix
(
objKey
,
key
)
{
return
false
}
return
f
ilter
.
Filter
(
obj
)
return
f
(
obj
)
}
return
NewSimpleFilter
(
filterFunc
,
filter
.
Trigger
)
return
filterFunc
}
// Returns resource version to which the underlying cache is synced.
...
...
@@ -603,12 +604,12 @@ type cacheWatcher struct {
sync
.
Mutex
input
chan
watchCacheEvent
result
chan
watch
.
Event
filter
Filter
filter
Filter
Func
stopped
bool
forget
func
(
bool
)
}
func
newCacheWatcher
(
resourceVersion
uint64
,
initEvents
[]
watchCacheEvent
,
filter
Filter
,
forget
func
(
bool
))
*
cacheWatcher
{
func
newCacheWatcher
(
resourceVersion
uint64
,
initEvents
[]
watchCacheEvent
,
filter
Filter
Func
,
forget
func
(
bool
))
*
cacheWatcher
{
watcher
:=
&
cacheWatcher
{
input
:
make
(
chan
watchCacheEvent
,
10
),
result
:
make
(
chan
watch
.
Event
,
10
),
...
...
@@ -684,10 +685,10 @@ func (c *cacheWatcher) add(event *watchCacheEvent) {
}
func
(
c
*
cacheWatcher
)
sendWatchCacheEvent
(
event
watchCacheEvent
)
{
curObjPasses
:=
event
.
Type
!=
watch
.
Deleted
&&
c
.
filter
.
Filter
(
event
.
Object
)
curObjPasses
:=
event
.
Type
!=
watch
.
Deleted
&&
c
.
filter
(
event
.
Object
)
oldObjPasses
:=
false
if
event
.
PrevObject
!=
nil
{
oldObjPasses
=
c
.
filter
.
Filter
(
event
.
PrevObject
)
oldObjPasses
=
c
.
filter
(
event
.
PrevObject
)
}
if
!
curObjPasses
&&
!
oldObjPasses
{
// Watcher is not interested in that object.
...
...
pkg/storage/cacher_test.go
View file @
6f3ac807
...
...
@@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/api/testapi"
apitesting
"k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
...
...
@@ -196,12 +197,12 @@ type injectListError struct {
storage
.
Interface
}
func
(
self
*
injectListError
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
self
*
injectListError
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
p
storage
.
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
if
self
.
errors
>
0
{
self
.
errors
--
return
fmt
.
Errorf
(
"injected error"
)
}
return
self
.
Interface
.
List
(
ctx
,
key
,
resourceVersion
,
filter
,
listObj
)
return
self
.
Interface
.
List
(
ctx
,
key
,
resourceVersion
,
p
,
listObj
)
}
func
TestWatch
(
t
*
testing
.
T
)
{
...
...
@@ -355,17 +356,18 @@ func TestFiltering(t *testing.T) {
}
// Set up Watch for object "podFoo" with label filter set.
selector
:=
labels
.
SelectorFromSet
(
labels
.
Set
{
"filter"
:
"foo"
})
filterFunc
:=
func
(
obj
runtime
.
Object
)
bool
{
metadata
,
err
:=
meta
.
Accessor
(
obj
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
return
false
}
return
selector
.
Matches
(
labels
.
Set
(
metadata
.
GetLabels
()))
}
filter
:=
storage
.
NewSimpleFilter
(
filterFunc
,
storage
.
NoTriggerFunc
)
watcher
,
err
:=
cacher
.
Watch
(
context
.
TODO
(),
"pods/ns/foo"
,
fooCreated
.
ResourceVersion
,
filter
)
pred
:=
storage
.
SelectionPredicate
{
Label
:
labels
.
SelectorFromSet
(
labels
.
Set
{
"filter"
:
"foo"
}),
Field
:
fields
.
Everything
(),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
label
labels
.
Set
,
field
fields
.
Set
,
err
error
)
{
metadata
,
err
:=
meta
.
Accessor
(
obj
)
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected error: %v"
,
err
)
}
return
labels
.
Set
(
metadata
.
GetLabels
()),
nil
,
nil
},
}
watcher
,
err
:=
cacher
.
Watch
(
context
.
TODO
(),
"pods/ns/foo"
,
fooCreated
.
ResourceVersion
,
pred
)
if
err
!=
nil
{
t
.
Fatalf
(
"Unexpected error: %v"
,
err
)
}
...
...
pkg/storage/etcd/etcd_helper.go
View file @
6f3ac807
...
...
@@ -202,7 +202,7 @@ func (h *etcdHelper) Delete(ctx context.Context, key string, out runtime.Object,
}
// Implements storage.Interface.
func
(
h
*
etcdHelper
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
)
(
watch
.
Interface
,
error
)
{
func
(
h
*
etcdHelper
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
if
ctx
==
nil
{
glog
.
Errorf
(
"Context is nil"
)
}
...
...
@@ -211,13 +211,13 @@ func (h *etcdHelper) Watch(ctx context.Context, key string, resourceVersion stri
return
nil
,
err
}
key
=
h
.
prefixEtcdKey
(
key
)
w
:=
newEtcdWatcher
(
false
,
h
.
quorum
,
nil
,
filter
,
h
.
codec
,
h
.
versioner
,
nil
,
h
)
w
:=
newEtcdWatcher
(
false
,
h
.
quorum
,
nil
,
storage
.
SimpleFilter
(
pred
)
,
h
.
codec
,
h
.
versioner
,
nil
,
h
)
go
w
.
etcdWatch
(
ctx
,
h
.
etcdKeysAPI
,
key
,
watchRV
)
return
w
,
nil
}
// Implements storage.Interface.
func
(
h
*
etcdHelper
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
)
(
watch
.
Interface
,
error
)
{
func
(
h
*
etcdHelper
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
if
ctx
==
nil
{
glog
.
Errorf
(
"Context is nil"
)
}
...
...
@@ -226,7 +226,7 @@ func (h *etcdHelper) WatchList(ctx context.Context, key string, resourceVersion
return
nil
,
err
}
key
=
h
.
prefixEtcdKey
(
key
)
w
:=
newEtcdWatcher
(
true
,
h
.
quorum
,
exceptKey
(
key
),
filter
,
h
.
codec
,
h
.
versioner
,
nil
,
h
)
w
:=
newEtcdWatcher
(
true
,
h
.
quorum
,
exceptKey
(
key
),
storage
.
SimpleFilter
(
pred
)
,
h
.
codec
,
h
.
versioner
,
nil
,
h
)
go
w
.
etcdWatch
(
ctx
,
h
.
etcdKeysAPI
,
key
,
watchRV
)
return
w
,
nil
}
...
...
@@ -297,7 +297,7 @@ func (h *etcdHelper) extractObj(response *etcd.Response, inErr error, objPtr run
}
// Implements storage.Interface.
func
(
h
*
etcdHelper
)
GetToList
(
ctx
context
.
Context
,
key
string
,
filter
storage
.
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
h
*
etcdHelper
)
GetToList
(
ctx
context
.
Context
,
key
string
,
pred
storage
.
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
if
ctx
==
nil
{
glog
.
Errorf
(
"Context is nil"
)
}
...
...
@@ -326,7 +326,7 @@ func (h *etcdHelper) GetToList(ctx context.Context, key string, filter storage.F
nodes
:=
make
([]
*
etcd
.
Node
,
0
)
nodes
=
append
(
nodes
,
response
.
Node
)
if
err
:=
h
.
decodeNodeList
(
nodes
,
filter
,
listPtr
);
err
!=
nil
{
if
err
:=
h
.
decodeNodeList
(
nodes
,
storage
.
SimpleFilter
(
pred
)
,
listPtr
);
err
!=
nil
{
return
err
}
trace
.
Step
(
"Object decoded"
)
...
...
@@ -337,7 +337,7 @@ func (h *etcdHelper) GetToList(ctx context.Context, key string, filter storage.F
}
// decodeNodeList walks the tree of each node in the list and decodes into the specified object
func
(
h
*
etcdHelper
)
decodeNodeList
(
nodes
[]
*
etcd
.
Node
,
filter
storage
.
Filter
,
slicePtr
interface
{})
error
{
func
(
h
*
etcdHelper
)
decodeNodeList
(
nodes
[]
*
etcd
.
Node
,
filter
storage
.
Filter
Func
,
slicePtr
interface
{})
error
{
trace
:=
util
.
NewTrace
(
"decodeNodeList "
+
getTypeName
(
slicePtr
))
defer
trace
.
LogIfLong
(
400
*
time
.
Millisecond
)
v
,
err
:=
conversion
.
EnforcePtr
(
slicePtr
)
...
...
@@ -366,7 +366,7 @@ func (h *etcdHelper) decodeNodeList(nodes []*etcd.Node, filter storage.Filter, s
}
// being unable to set the version does not prevent the object from being extracted
_
=
h
.
versioner
.
UpdateObject
(
obj
,
node
.
ModifiedIndex
)
if
filter
.
Filter
(
obj
)
{
if
filter
(
obj
)
{
v
.
Set
(
reflect
.
Append
(
v
,
reflect
.
ValueOf
(
obj
)
.
Elem
()))
}
if
node
.
ModifiedIndex
!=
0
{
...
...
@@ -379,7 +379,7 @@ func (h *etcdHelper) decodeNodeList(nodes []*etcd.Node, filter storage.Filter, s
}
// Implements storage.Interface.
func
(
h
*
etcdHelper
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
h
*
etcdHelper
)
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
if
ctx
==
nil
{
glog
.
Errorf
(
"Context is nil"
)
}
...
...
@@ -398,7 +398,7 @@ func (h *etcdHelper) List(ctx context.Context, key string, resourceVersion strin
if
err
!=
nil
{
return
err
}
if
err
:=
h
.
decodeNodeList
(
nodes
,
filter
,
listPtr
);
err
!=
nil
{
if
err
:=
h
.
decodeNodeList
(
nodes
,
storage
.
SimpleFilter
(
pred
)
,
listPtr
);
err
!=
nil
{
return
err
}
trace
.
Step
(
"Node list decoded"
)
...
...
@@ -548,7 +548,7 @@ func (h *etcdHelper) prefixEtcdKey(key string) string {
// their Node.ModifiedIndex, which is unique across all types.
// All implementations must be thread-safe.
type
etcdCache
interface
{
getFromCache
(
index
uint64
,
filter
storage
.
Filter
)
(
runtime
.
Object
,
bool
)
getFromCache
(
index
uint64
,
filter
storage
.
Filter
Func
)
(
runtime
.
Object
,
bool
)
addToCache
(
index
uint64
,
obj
runtime
.
Object
)
}
...
...
@@ -556,14 +556,14 @@ func getTypeName(obj interface{}) string {
return
reflect
.
TypeOf
(
obj
)
.
String
()
}
func
(
h
*
etcdHelper
)
getFromCache
(
index
uint64
,
filter
storage
.
Filter
)
(
runtime
.
Object
,
bool
)
{
func
(
h
*
etcdHelper
)
getFromCache
(
index
uint64
,
filter
storage
.
Filter
Func
)
(
runtime
.
Object
,
bool
)
{
startTime
:=
time
.
Now
()
defer
func
()
{
metrics
.
ObserveGetCache
(
startTime
)
}()
obj
,
found
:=
h
.
cache
.
Get
(
index
)
if
found
{
if
!
filter
.
Filter
(
obj
.
(
runtime
.
Object
))
{
if
!
filter
(
obj
.
(
runtime
.
Object
))
{
return
nil
,
true
}
// We should not return the object itself to avoid polluting the cache if someone
...
...
pkg/storage/etcd/etcd_helper_test.go
View file @
6f3ac807
...
...
@@ -30,6 +30,8 @@ import (
"k8s.io/kubernetes/pkg/api/testapi"
apitesting
"k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/serializer"
"k8s.io/kubernetes/pkg/storage"
...
...
@@ -154,14 +156,17 @@ func TestListFiltered(t *testing.T) {
}
createPodList
(
t
,
helper
,
&
list
)
filterFunc
:=
func
(
obj
runtime
.
Object
)
bool
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
pod
.
Name
==
"bar"
// List only "bar" pod
p
:=
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
SelectorFromSet
(
fields
.
Set
{
"metadata.name"
:
"bar"
}),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
labels
.
Set
(
pod
.
Labels
),
fields
.
Set
{
"metadata.name"
:
pod
.
Name
},
nil
},
}
filter
:=
storage
.
NewSimpleFilter
(
filterFunc
,
storage
.
NoTriggerFunc
)
var
got
api
.
PodList
err
:=
helper
.
List
(
context
.
TODO
(),
key
,
""
,
filter
,
&
got
)
err
:=
helper
.
List
(
context
.
TODO
(),
key
,
""
,
p
,
&
got
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v"
,
err
)
}
...
...
pkg/storage/etcd/etcd_watcher.go
View file @
6f3ac807
...
...
@@ -77,7 +77,7 @@ type etcdWatcher struct {
list
bool
// If we're doing a recursive watch, should be true.
quorum
bool
// If we enable quorum, shoule be true
include
includeFunc
filter
storage
.
Filter
filter
storage
.
Filter
Func
etcdIncoming
chan
*
etcd
.
Response
etcdError
chan
error
...
...
@@ -105,7 +105,7 @@ const watchWaitDuration = 100 * time.Millisecond
// newEtcdWatcher returns a new etcdWatcher; if list is true, watch sub-nodes.
// The versioner must be able to handle the objects that transform creates.
func
newEtcdWatcher
(
list
bool
,
quorum
bool
,
include
includeFunc
,
filter
storage
.
Filter
,
list
bool
,
quorum
bool
,
include
includeFunc
,
filter
storage
.
Filter
Func
,
encoding
runtime
.
Codec
,
versioner
storage
.
Versioner
,
transform
TransformFunc
,
cache
etcdCache
)
*
etcdWatcher
{
w
:=
&
etcdWatcher
{
...
...
@@ -310,7 +310,7 @@ func (w *etcdWatcher) translate() {
}
func
(
w
*
etcdWatcher
)
decodeObject
(
node
*
etcd
.
Node
)
(
runtime
.
Object
,
error
)
{
if
obj
,
found
:=
w
.
cache
.
getFromCache
(
node
.
ModifiedIndex
,
storage
.
Everything
);
found
{
if
obj
,
found
:=
w
.
cache
.
getFromCache
(
node
.
ModifiedIndex
,
storage
.
SimpleFilter
(
storage
.
Everything
)
);
found
{
return
obj
,
nil
}
...
...
@@ -355,7 +355,7 @@ func (w *etcdWatcher) sendAdd(res *etcd.Response) {
// the resourceVersion to resume will never be able to get past a bad value.
return
}
if
!
w
.
filter
.
Filter
(
obj
)
{
if
!
w
.
filter
(
obj
)
{
return
}
action
:=
watch
.
Added
...
...
@@ -384,7 +384,7 @@ func (w *etcdWatcher) sendModify(res *etcd.Response) {
// the resourceVersion to resume will never be able to get past a bad value.
return
}
curObjPasses
:=
w
.
filter
.
Filter
(
curObj
)
curObjPasses
:=
w
.
filter
(
curObj
)
oldObjPasses
:=
false
var
oldObj
runtime
.
Object
if
res
.
PrevNode
!=
nil
&&
res
.
PrevNode
.
Value
!=
""
{
...
...
@@ -393,7 +393,7 @@ func (w *etcdWatcher) sendModify(res *etcd.Response) {
if
err
:=
w
.
versioner
.
UpdateObject
(
oldObj
,
res
.
Node
.
ModifiedIndex
);
err
!=
nil
{
utilruntime
.
HandleError
(
fmt
.
Errorf
(
"failure to version api object (%d) %#v: %v"
,
res
.
Node
.
ModifiedIndex
,
oldObj
,
err
))
}
oldObjPasses
=
w
.
filter
.
Filter
(
oldObj
)
oldObjPasses
=
w
.
filter
(
oldObj
)
}
}
// Some changes to an object may cause it to start or stop matching a filter.
...
...
@@ -442,7 +442,7 @@ func (w *etcdWatcher) sendDelete(res *etcd.Response) {
// the resourceVersion to resume will never be able to get past a bad value.
return
}
if
!
w
.
filter
.
Filter
(
obj
)
{
if
!
w
.
filter
(
obj
)
{
return
}
w
.
emit
(
watch
.
Event
{
...
...
pkg/storage/etcd/etcd_watcher_test.go
View file @
6f3ac807
...
...
@@ -37,7 +37,7 @@ var versioner = APIObjectVersioner{}
// Implements etcdCache interface as empty methods (i.e. does not cache any objects)
type
fakeEtcdCache
struct
{}
func
(
f
*
fakeEtcdCache
)
getFromCache
(
index
uint64
,
filter
storage
.
Filter
)
(
runtime
.
Object
,
bool
)
{
func
(
f
*
fakeEtcdCache
)
getFromCache
(
index
uint64
,
filter
storage
.
Filter
Func
)
(
runtime
.
Object
,
bool
)
{
return
nil
,
false
}
...
...
@@ -46,18 +46,6 @@ func (f *fakeEtcdCache) addToCache(index uint64, obj runtime.Object) {
var
_
etcdCache
=
&
fakeEtcdCache
{}
// firstLetterIsB implements storage.Filter interface.
type
firstLetterIsB
struct
{
}
func
(
f
*
firstLetterIsB
)
Filter
(
obj
runtime
.
Object
)
bool
{
return
obj
.
(
*
api
.
Pod
)
.
Name
[
0
]
==
'b'
}
func
(
f
*
firstLetterIsB
)
Trigger
()
[]
storage
.
MatchValue
{
return
nil
}
func
TestWatchInterpretations
(
t
*
testing
.
T
)
{
codec
:=
testapi
.
Default
.
Codec
()
// Declare some pods to make the test cases compact.
...
...
@@ -135,10 +123,12 @@ func TestWatchInterpretations(t *testing.T) {
expectEmit
:
false
,
},
}
firstLetterIsB
:=
func
(
obj
runtime
.
Object
)
bool
{
return
obj
.
(
*
api
.
Pod
)
.
Name
[
0
]
==
'b'
}
for
name
,
item
:=
range
table
{
for
_
,
action
:=
range
item
.
actions
{
w
:=
newEtcdWatcher
(
true
,
false
,
nil
,
&
firstLetterIsB
{}
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
:=
newEtcdWatcher
(
true
,
false
,
nil
,
firstLetterIsB
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
emitCalled
:=
false
w
.
emit
=
func
(
event
watch
.
Event
)
{
emitCalled
=
true
...
...
@@ -177,7 +167,7 @@ func TestWatchInterpretations(t *testing.T) {
func
TestWatchInterpretation_ResponseNotSet
(
t
*
testing
.
T
)
{
_
,
codec
:=
testScheme
(
t
)
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
Everything
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
SimpleFilter
(
storage
.
Everything
)
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
.
emit
=
func
(
e
watch
.
Event
)
{
t
.
Errorf
(
"Unexpected emit: %v"
,
e
)
}
...
...
@@ -192,7 +182,7 @@ func TestWatchInterpretation_ResponseNoNode(t *testing.T) {
_
,
codec
:=
testScheme
(
t
)
actions
:=
[]
string
{
"create"
,
"set"
,
"compareAndSwap"
,
"delete"
}
for
_
,
action
:=
range
actions
{
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
Everything
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
SimpleFilter
(
storage
.
Everything
)
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
.
emit
=
func
(
e
watch
.
Event
)
{
t
.
Errorf
(
"Unexpected emit: %v"
,
e
)
}
...
...
@@ -207,7 +197,7 @@ func TestWatchInterpretation_ResponseBadData(t *testing.T) {
_
,
codec
:=
testScheme
(
t
)
actions
:=
[]
string
{
"create"
,
"set"
,
"compareAndSwap"
,
"delete"
}
for
_
,
action
:=
range
actions
{
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
Everything
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
storage
.
SimpleFilter
(
storage
.
Everything
)
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
w
.
emit
=
func
(
e
watch
.
Event
)
{
t
.
Errorf
(
"Unexpected emit: %v"
,
e
)
}
...
...
@@ -229,10 +219,9 @@ func TestWatchInterpretation_ResponseBadData(t *testing.T) {
func
TestSendResultDeleteEventHaveLatestIndex
(
t
*
testing
.
T
)
{
codec
:=
testapi
.
Default
.
Codec
()
filter
Func
:=
func
(
obj
runtime
.
Object
)
bool
{
filter
:=
func
(
obj
runtime
.
Object
)
bool
{
return
obj
.
(
*
api
.
Pod
)
.
Name
!=
"bar"
}
filter
:=
storage
.
NewSimpleFilter
(
filterFunc
,
storage
.
NoTriggerFunc
)
w
:=
newEtcdWatcher
(
false
,
false
,
nil
,
filter
,
codec
,
versioner
,
nil
,
&
fakeEtcdCache
{})
eventChan
:=
make
(
chan
watch
.
Event
,
1
)
...
...
pkg/storage/etcd3/store.go
View file @
6f3ac807
...
...
@@ -255,7 +255,7 @@ func (s *store) GuaranteedUpdate(ctx context.Context, key string, out runtime.Ob
}
// GetToList implements storage.Interface.GetToList.
func
(
s
*
store
)
GetToList
(
ctx
context
.
Context
,
key
string
,
filter
storage
.
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
s
*
store
)
GetToList
(
ctx
context
.
Context
,
key
string
,
pred
storage
.
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
listPtr
,
err
:=
meta
.
GetItemsPtr
(
listObj
)
if
err
!=
nil
{
return
err
...
...
@@ -273,7 +273,7 @@ func (s *store) GetToList(ctx context.Context, key string, filter storage.Filter
data
:
getResp
.
Kvs
[
0
]
.
Value
,
rev
:
uint64
(
getResp
.
Kvs
[
0
]
.
ModRevision
),
}}
if
err
:=
decodeList
(
elems
,
filter
,
listPtr
,
s
.
codec
,
s
.
versioner
);
err
!=
nil
{
if
err
:=
decodeList
(
elems
,
storage
.
SimpleFilter
(
pred
)
,
listPtr
,
s
.
codec
,
s
.
versioner
);
err
!=
nil
{
return
err
}
// update version with cluster level revision
...
...
@@ -281,7 +281,7 @@ func (s *store) GetToList(ctx context.Context, key string, filter storage.Filter
}
// List implements storage.Interface.List.
func
(
s
*
store
)
List
(
ctx
context
.
Context
,
key
,
resourceVersion
string
,
filter
storage
.
Filter
,
listObj
runtime
.
Object
)
error
{
func
(
s
*
store
)
List
(
ctx
context
.
Context
,
key
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
,
listObj
runtime
.
Object
)
error
{
listPtr
,
err
:=
meta
.
GetItemsPtr
(
listObj
)
if
err
!=
nil
{
return
err
...
...
@@ -305,7 +305,7 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, filter st
rev
:
uint64
(
kv
.
ModRevision
),
}
}
if
err
:=
decodeList
(
elems
,
filter
,
listPtr
,
s
.
codec
,
s
.
versioner
);
err
!=
nil
{
if
err
:=
decodeList
(
elems
,
storage
.
SimpleFilter
(
pred
)
,
listPtr
,
s
.
codec
,
s
.
versioner
);
err
!=
nil
{
return
err
}
// update version with cluster level revision
...
...
@@ -313,16 +313,16 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, filter st
}
// Watch implements storage.Interface.Watch.
func
(
s
*
store
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
)
(
watch
.
Interface
,
error
)
{
return
s
.
watch
(
ctx
,
key
,
resourceVersion
,
filter
,
false
)
func
(
s
*
store
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
return
s
.
watch
(
ctx
,
key
,
resourceVersion
,
storage
.
SimpleFilter
(
pred
)
,
false
)
}
// WatchList implements storage.Interface.WatchList.
func
(
s
*
store
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
storage
.
Filter
)
(
watch
.
Interface
,
error
)
{
return
s
.
watch
(
ctx
,
key
,
resourceVersion
,
filter
,
true
)
func
(
s
*
store
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
pred
storage
.
SelectionPredicate
)
(
watch
.
Interface
,
error
)
{
return
s
.
watch
(
ctx
,
key
,
resourceVersion
,
storage
.
SimpleFilter
(
pred
)
,
true
)
}
func
(
s
*
store
)
watch
(
ctx
context
.
Context
,
key
string
,
rv
string
,
filter
storage
.
Filter
,
recursive
bool
)
(
watch
.
Interface
,
error
)
{
func
(
s
*
store
)
watch
(
ctx
context
.
Context
,
key
string
,
rv
string
,
filter
storage
.
Filter
Func
,
recursive
bool
)
(
watch
.
Interface
,
error
)
{
rev
,
err
:=
storage
.
ParseWatchResourceVersion
(
rv
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -416,7 +416,7 @@ func decode(codec runtime.Codec, versioner storage.Versioner, value []byte, objP
// decodeList decodes a list of values into a list of objects, with resource version set to corresponding rev.
// On success, ListPtr would be set to the list of objects.
func
decodeList
(
elems
[]
*
elemForDecode
,
filter
storage
.
Filter
,
ListPtr
interface
{},
codec
runtime
.
Codec
,
versioner
storage
.
Versioner
)
error
{
func
decodeList
(
elems
[]
*
elemForDecode
,
filter
storage
.
Filter
Func
,
ListPtr
interface
{},
codec
runtime
.
Codec
,
versioner
storage
.
Versioner
)
error
{
v
,
err
:=
conversion
.
EnforcePtr
(
ListPtr
)
if
err
!=
nil
||
v
.
Kind
()
!=
reflect
.
Slice
{
panic
(
"need ptr to slice"
)
...
...
@@ -428,7 +428,7 @@ func decodeList(elems []*elemForDecode, filter storage.Filter, ListPtr interface
}
// being unable to set the version does not prevent the object from being extracted
versioner
.
UpdateObject
(
obj
,
elem
.
rev
)
if
filter
.
Filter
(
obj
)
{
if
filter
(
obj
)
{
v
.
Set
(
reflect
.
Append
(
v
,
reflect
.
ValueOf
(
obj
)
.
Elem
()))
}
}
...
...
pkg/storage/etcd3/store_test.go
View file @
6f3ac807
...
...
@@ -24,6 +24,8 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
...
...
@@ -226,36 +228,32 @@ func TestGetToList(t *testing.T) {
tests
:=
[]
struct
{
key
string
filter
func
(
runtime
.
Object
)
bool
trigger
func
()
[]
storage
.
MatchValue
pred
storage
.
SelectionPredicate
expectedOut
[]
*
api
.
Pod
}{{
// test GetToList on existing key
key
:
key
,
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
expectedOut
:
[]
*
api
.
Pod
{
storedObj
},
},
{
// test GetToList on non-existing key
key
:
"/non-existing"
,
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
expectedOut
:
nil
,
},
{
// test GetToList with
filter to reject the pod
},
{
// test GetToList with
matching pod name
key
:
"/non-existing"
,
filter
:
func
(
obj
runtime
.
Object
)
bool
{
pod
,
ok
:=
obj
.
(
*
api
.
Pod
)
if
!
ok
{
t
.
Fatal
(
"It should be able to convert obj to *api.Pod"
)
}
return
pod
.
Name
!=
storedObj
.
Name
pred
:
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
ParseSelectorOrDie
(
"metadata.name!="
+
storedObj
.
Name
),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
nil
,
fields
.
Set
{
"metadata.name"
:
pod
.
Name
},
nil
},
},
trigger
:
storage
.
NoTriggerFunc
,
expectedOut
:
nil
,
}}
for
i
,
tt
:=
range
tests
{
out
:=
&
api
.
PodList
{}
filter
:=
storage
.
NewSimpleFilter
(
tt
.
filter
,
tt
.
trigger
)
err
:=
store
.
GetToList
(
ctx
,
tt
.
key
,
filter
,
out
)
err
:=
store
.
GetToList
(
ctx
,
tt
.
key
,
tt
.
pred
,
out
)
if
err
!=
nil
{
t
.
Fatalf
(
"GetToList failed: %v"
,
err
)
}
...
...
@@ -492,41 +490,36 @@ func TestList(t *testing.T) {
tests
:=
[]
struct
{
prefix
string
filter
func
(
runtime
.
Object
)
bool
trigger
func
()
[]
storage
.
MatchValue
pred
storage
.
SelectionPredicate
expectedOut
[]
*
api
.
Pod
}{{
// test List on existing key
prefix
:
"/one-level/"
,
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
expectedOut
:
[]
*
api
.
Pod
{
preset
[
0
]
.
storedObj
},
},
{
// test List on non-existing key
prefix
:
"/non-existing/"
,
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
expectedOut
:
nil
,
},
{
// test List with
filter
},
{
// test List with
pod name matching
prefix
:
"/one-level/"
,
filter
:
func
(
obj
runtime
.
Object
)
bool
{
pod
,
ok
:=
obj
.
(
*
api
.
Pod
)
if
!
ok
{
t
.
Fatal
(
"It should be able to convert obj to *api.Pod"
)
}
return
pod
.
Name
!=
preset
[
0
]
.
storedObj
.
Name
pred
:
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
ParseSelectorOrDie
(
"metadata.name!="
+
preset
[
0
]
.
storedObj
.
Name
),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
nil
,
fields
.
Set
{
"metadata.name"
:
pod
.
Name
},
nil
},
},
trigger
:
storage
.
NoTriggerFunc
,
expectedOut
:
nil
,
},
{
// test List with multiple levels of directories and expect flattened result
prefix
:
"/two-level/"
,
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
expectedOut
:
[]
*
api
.
Pod
{
preset
[
1
]
.
storedObj
,
preset
[
2
]
.
storedObj
},
}}
for
i
,
tt
:=
range
tests
{
out
:=
&
api
.
PodList
{}
filter
:=
storage
.
NewSimpleFilter
(
tt
.
filter
,
tt
.
trigger
)
err
:=
store
.
List
(
ctx
,
tt
.
prefix
,
"0"
,
filter
,
out
)
err
:=
store
.
List
(
ctx
,
tt
.
prefix
,
"0"
,
tt
.
pred
,
out
)
if
err
!=
nil
{
t
.
Fatalf
(
"List failed: %v"
,
err
)
}
...
...
pkg/storage/etcd3/watcher.go
View file @
6f3ac807
...
...
@@ -51,7 +51,7 @@ type watchChan struct {
key
string
initialRev
int64
recursive
bool
filter
storage
.
Filter
filter
storage
.
Filter
Func
ctx
context
.
Context
cancel
context
.
CancelFunc
incomingEventChan
chan
*
event
...
...
@@ -74,7 +74,7 @@ func newWatcher(client *clientv3.Client, codec runtime.Codec, versioner storage.
// If recursive is false, it watches on given key.
// If recursive is true, it watches any children and directories under the key, excluding the root key itself.
// filter must be non-nil. Only if filter returns true will the changes be returned.
func
(
w
*
watcher
)
Watch
(
ctx
context
.
Context
,
key
string
,
rev
int64
,
recursive
bool
,
filter
storage
.
Filter
)
(
watch
.
Interface
,
error
)
{
func
(
w
*
watcher
)
Watch
(
ctx
context
.
Context
,
key
string
,
rev
int64
,
recursive
bool
,
filter
storage
.
Filter
Func
)
(
watch
.
Interface
,
error
)
{
if
recursive
&&
!
strings
.
HasSuffix
(
key
,
"/"
)
{
key
+=
"/"
}
...
...
@@ -83,7 +83,7 @@ func (w *watcher) Watch(ctx context.Context, key string, rev int64, recursive bo
return
wc
,
nil
}
func
(
w
*
watcher
)
createWatchChan
(
ctx
context
.
Context
,
key
string
,
rev
int64
,
recursive
bool
,
filter
storage
.
Filter
)
*
watchChan
{
func
(
w
*
watcher
)
createWatchChan
(
ctx
context
.
Context
,
key
string
,
rev
int64
,
recursive
bool
,
filter
storage
.
Filter
Func
)
*
watchChan
{
wc
:=
&
watchChan
{
watcher
:
w
,
key
:
key
,
...
...
@@ -241,7 +241,7 @@ func (wc *watchChan) transform(e *event) (res *watch.Event) {
switch
{
case
e
.
isDeleted
:
if
!
wc
.
filter
.
Filter
(
oldObj
)
{
if
!
wc
.
filter
(
oldObj
)
{
return
nil
}
res
=
&
watch
.
Event
{
...
...
@@ -249,7 +249,7 @@ func (wc *watchChan) transform(e *event) (res *watch.Event) {
Object
:
oldObj
,
}
case
e
.
isCreated
:
if
!
wc
.
filter
.
Filter
(
curObj
)
{
if
!
wc
.
filter
(
curObj
)
{
return
nil
}
res
=
&
watch
.
Event
{
...
...
@@ -257,8 +257,8 @@ func (wc *watchChan) transform(e *event) (res *watch.Event) {
Object
:
curObj
,
}
default
:
curObjPasses
:=
wc
.
filter
.
Filter
(
curObj
)
oldObjPasses
:=
wc
.
filter
.
Filter
(
oldObj
)
curObjPasses
:=
wc
.
filter
(
curObj
)
oldObjPasses
:=
wc
.
filter
(
oldObj
)
switch
{
case
curObjPasses
&&
oldObjPasses
:
res
=
&
watch
.
Event
{
...
...
pkg/storage/etcd3/watcher_test.go
View file @
6f3ac807
...
...
@@ -30,6 +30,8 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
"k8s.io/kubernetes/pkg/util/wait"
...
...
@@ -54,45 +56,42 @@ func testWatch(t *testing.T, recursive bool) {
tests
:=
[]
struct
{
key
string
filter
func
(
runtime
.
Object
)
bool
trigger
func
()
[]
storage
.
MatchValue
pred
storage
.
SelectionPredicate
watchTests
[]
*
testWatchStruct
}{{
// create a key
key
:
"/somekey-1"
,
watchTests
:
[]
*
testWatchStruct
{{
podFoo
,
true
,
watch
.
Added
}},
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
},
{
// create a key but obj gets filtered
key
:
"/somekey-2"
,
watchTests
:
[]
*
testWatchStruct
{{
podFoo
,
false
,
""
}},
filter
:
func
(
runtime
.
Object
)
bool
{
return
false
},
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
},
{
// create a key but obj gets filtered. Then update it with unfiltered obj
key
:
"/somekey-3"
,
watchTests
:
[]
*
testWatchStruct
{{
podFoo
,
false
,
""
},
{
podBar
,
true
,
watch
.
Added
}},
filter
:
func
(
obj
runtime
.
Object
)
bool
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
pod
.
Name
==
"bar"
pred
:
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
ParseSelectorOrDie
(
"metadata.name=bar"
),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
nil
,
fields
.
Set
{
"metadata.name"
:
pod
.
Name
},
nil
},
},
trigger
:
storage
.
NoTriggerFunc
,
},
{
// update
key
:
"/somekey-4"
,
watchTests
:
[]
*
testWatchStruct
{{
podFoo
,
true
,
watch
.
Added
},
{
podBar
,
true
,
watch
.
Modified
}},
filter
:
storage
.
EverythingFunc
,
trigger
:
storage
.
NoTriggerFunc
,
pred
:
storage
.
Everything
,
},
{
// delete because of being filtered
key
:
"/somekey-5"
,
watchTests
:
[]
*
testWatchStruct
{{
podFoo
,
true
,
watch
.
Added
},
{
podBar
,
true
,
watch
.
Deleted
}},
filter
:
func
(
obj
runtime
.
Object
)
bool
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
pod
.
Name
!=
"bar"
pred
:
storage
.
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
ParseSelectorOrDie
(
"metadata.name!=bar"
),
GetAttrs
:
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
{
pod
:=
obj
.
(
*
api
.
Pod
)
return
nil
,
fields
.
Set
{
"metadata.name"
:
pod
.
Name
},
nil
},
},
trigger
:
storage
.
NoTriggerFunc
,
}}
for
i
,
tt
:=
range
tests
{
ctx
,
store
,
cluster
:=
testSetup
(
t
)
filter
:=
storage
.
NewSimpleFilter
(
tt
.
filter
,
tt
.
trigger
)
w
,
err
:=
store
.
watch
(
ctx
,
tt
.
key
,
"0"
,
filter
,
recursive
)
w
,
err
:=
store
.
watch
(
ctx
,
tt
.
key
,
"0"
,
storage
.
SimpleFilter
(
tt
.
pred
),
recursive
)
if
err
!=
nil
{
t
.
Fatalf
(
"Watch failed: %v"
,
err
)
}
...
...
@@ -198,7 +197,7 @@ func TestWatchContextCancel(t *testing.T) {
cancel
()
// When we watch with a canceled context, we should detect that it's context canceled.
// We won't take it as error and also close the watcher.
w
,
err
:=
store
.
watcher
.
Watch
(
canceledCtx
,
"/abc"
,
0
,
false
,
storage
.
Everything
)
w
,
err
:=
store
.
watcher
.
Watch
(
canceledCtx
,
"/abc"
,
0
,
false
,
storage
.
SimpleFilter
(
storage
.
Everything
)
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
...
...
@@ -217,7 +216,7 @@ func TestWatchErrResultNotBlockAfterCancel(t *testing.T) {
origCtx
,
store
,
cluster
:=
testSetup
(
t
)
defer
cluster
.
Terminate
(
t
)
ctx
,
cancel
:=
context
.
WithCancel
(
origCtx
)
w
:=
store
.
watcher
.
createWatchChan
(
ctx
,
"/abc"
,
0
,
false
,
storage
.
Everything
)
w
:=
store
.
watcher
.
createWatchChan
(
ctx
,
"/abc"
,
0
,
false
,
storage
.
SimpleFilter
(
storage
.
Everything
)
)
// make resutlChan and errChan blocking to ensure ordering.
w
.
resultChan
=
make
(
chan
watch
.
Event
)
w
.
errChan
=
make
(
chan
error
)
...
...
pkg/storage/interfaces.go
View file @
6f3ac807
...
...
@@ -18,6 +18,8 @@ package storage
import
(
"golang.org/x/net/context"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/watch"
...
...
@@ -62,34 +64,14 @@ type MatchValue struct {
// to that function.
type
TriggerPublisherFunc
func
(
obj
runtime
.
Object
)
[]
MatchValue
// Filter is interface that is used to pass filtering mechanism.
type
Filter
interface
{
// Filter is a predicate which takes an API object and returns true
// if and only if the object should remain in the set.
Filter
(
obj
runtime
.
Object
)
bool
// For any triggers known to the Filter, if Filter() can return only
// (a subset of) objects for which indexing function returns <value>,
// (<index name>, <value> pair would be returned.
//
// This is optimization to avoid computing Filter() function (which are
// usually relatively expensive) in case we are sure they will return
// false anyway.
Trigger
()
[]
MatchValue
}
// Everything is a Filter which accepts all objects.
var
Everything
Filter
=
everything
{}
// everything is implementation of Everything.
type
everything
struct
{
}
func
(
e
everything
)
Filter
(
runtime
.
Object
)
bool
{
return
true
}
// FilterFunc takes an API object and returns true if the object satisfies some requirements.
// TODO: We will remove this type and use SelectionPredicate everywhere.
type
FilterFunc
func
(
obj
runtime
.
Object
)
bool
func
(
e
everything
)
Trigger
()
[]
MatchValue
{
return
nil
// Everything accepts all objects.
var
Everything
=
SelectionPredicate
{
Label
:
labels
.
Everything
(),
Field
:
fields
.
Everything
(),
}
// Pass an UpdateFunc to Interface.GuaranteedUpdate to make an update
...
...
@@ -125,18 +107,18 @@ type Interface interface {
Delete
(
ctx
context
.
Context
,
key
string
,
out
runtime
.
Object
,
preconditions
*
Preconditions
)
error
// Watch begins watching the specified key. Events are decoded into API objects,
// and any items
passing 'filter
' are sent down to returned watch.Interface.
// and any items
selected by 'p
' are sent down to returned watch.Interface.
// resourceVersion may be used to specify what version to begin watching,
// which should be the current resourceVersion, and no longer rv+1
// (e.g. reconnecting without missing any updates).
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
)
(
watch
.
Interface
,
error
)
Watch
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
p
SelectionPredicate
)
(
watch
.
Interface
,
error
)
// WatchList begins watching the specified key's items. Items are decoded into API
// objects and any item
passing 'filter
' are sent down to returned watch.Interface.
// objects and any item
selected by 'p
' are sent down to returned watch.Interface.
// resourceVersion may be used to specify what version to begin watching,
// which should be the current resourceVersion, and no longer rv+1
// (e.g. reconnecting without missing any updates).
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
)
(
watch
.
Interface
,
error
)
WatchList
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
p
SelectionPredicate
)
(
watch
.
Interface
,
error
)
// Get unmarshals json found at key into objPtr. On a not found error, will either
// return a zero object of the requested type, or an error, depending on ignoreNotFound.
...
...
@@ -145,13 +127,13 @@ type Interface interface {
// GetToList unmarshals json found at key and opaque it into *List api object
// (an object that satisfies the runtime.IsList definition).
GetToList
(
ctx
context
.
Context
,
key
string
,
filter
Filter
,
listObj
runtime
.
Object
)
error
GetToList
(
ctx
context
.
Context
,
key
string
,
p
SelectionPredicate
,
listObj
runtime
.
Object
)
error
// List unmarshalls jsons found at directory defined by key and opaque them
// into *List api object (an object that satisfies runtime.IsList definition).
// The returned contents may be delayed, but it is guaranteed that they will
// be have at least 'resourceVersion'.
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
filter
Filter
,
listObj
runtime
.
Object
)
error
List
(
ctx
context
.
Context
,
key
string
,
resourceVersion
string
,
p
SelectionPredicate
,
listObj
runtime
.
Object
)
error
// GuaranteedUpdate keeps calling 'tryUpdate()' to update key 'key' (of type 'ptrToType')
// retrying the update until success if there is index conflict.
...
...
pkg/storage/selection_predicate.go
0 → 100644
View file @
6f3ac807
/*
Copyright 2016 The Kubernetes Authors.
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
storage
import
(
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
)
// AttrFunc returns label and field sets for List or Watch to match.
// In any failure to parse given object, it returns error.
type
AttrFunc
func
(
obj
runtime
.
Object
)
(
labels
.
Set
,
fields
.
Set
,
error
)
// SelectionPredicate is used to represent the way to select objects from api storage.
type
SelectionPredicate
struct
{
Label
labels
.
Selector
Field
fields
.
Selector
GetAttrs
AttrFunc
IndexFields
[]
string
}
// Matches returns true if the given object's labels and fields (as
// returned by s.GetAttrs) match s.Label and s.Field. An error is
// returned if s.GetAttrs fails.
func
(
s
*
SelectionPredicate
)
Matches
(
obj
runtime
.
Object
)
(
bool
,
error
)
{
if
s
.
Label
.
Empty
()
&&
s
.
Field
.
Empty
()
{
return
true
,
nil
}
labels
,
fields
,
err
:=
s
.
GetAttrs
(
obj
)
if
err
!=
nil
{
return
false
,
err
}
matched
:=
s
.
Label
.
Matches
(
labels
)
if
s
.
Field
!=
nil
{
matched
=
(
matched
&&
s
.
Field
.
Matches
(
fields
))
}
return
matched
,
nil
}
// MatchesSingle will return (name, true) if and only if s.Field matches on the object's
// name.
func
(
s
*
SelectionPredicate
)
MatchesSingle
()
(
string
,
bool
)
{
// TODO: should be namespace.name
if
name
,
ok
:=
s
.
Field
.
RequiresExactMatch
(
"metadata.name"
);
ok
{
return
name
,
true
}
return
""
,
false
}
// For any index defined by IndexFields, if a matcher can match only (a subset)
// of objects that return <value> for a given index, a pair (<index name>, <value>)
// wil be returned.
// TODO: Consider supporting also labels.
func
(
s
*
SelectionPredicate
)
MatcherIndex
()
[]
MatchValue
{
var
result
[]
MatchValue
for
_
,
field
:=
range
s
.
IndexFields
{
if
value
,
ok
:=
s
.
Field
.
RequiresExactMatch
(
field
);
ok
{
result
=
append
(
result
,
MatchValue
{
IndexName
:
field
,
Value
:
value
})
}
}
return
result
}
pkg/
registry/generic/matcher
_test.go
→
pkg/
storage/selection_predicate
_test.go
View file @
6f3ac807
/*
Copyright 201
4
The Kubernetes Authors.
Copyright 201
6
The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
...
...
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
generic
package
storage
import
(
"errors"
...
...
pkg/storage/util.go
View file @
6f3ac807
...
...
@@ -22,6 +22,8 @@ import (
"strings"
"sync/atomic"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/validation/path"
"k8s.io/kubernetes/pkg/runtime"
...
...
@@ -38,26 +40,16 @@ func SimpleUpdate(fn SimpleUpdateFunc) UpdateFunc {
}
}
// SimpleFilter implements Filter interface.
type
SimpleFilter
struct
{
filterFunc
func
(
runtime
.
Object
)
bool
triggerFunc
func
()
[]
MatchValue
}
func
(
s
*
SimpleFilter
)
Filter
(
obj
runtime
.
Object
)
bool
{
return
s
.
filterFunc
(
obj
)
}
func
(
s
*
SimpleFilter
)
Trigger
()
[]
MatchValue
{
return
s
.
triggerFunc
()
}
func
NewSimpleFilter
(
filterFunc
func
(
runtime
.
Object
)
bool
,
triggerFunc
func
()
[]
MatchValue
)
Filter
{
return
&
SimpleFilter
{
filterFunc
:
filterFunc
,
triggerFunc
:
triggerFunc
,
// SimpleFilter converts a selection predicate into a FilterFunc.
// It ignores any error from Matches().
func
SimpleFilter
(
p
SelectionPredicate
)
FilterFunc
{
return
func
(
obj
runtime
.
Object
)
bool
{
matches
,
err
:=
p
.
Matches
(
obj
)
if
err
!=
nil
{
glog
.
Errorf
(
"invalid object for matching. Obj: %v. Err: %v"
,
obj
,
err
)
return
false
}
return
matches
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment