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
29c50cdc
Commit
29c50cdc
authored
Oct 14, 2015
by
Mike Danese
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
plumb PodSelector through the api
parent
407f9b9e
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
262 additions
and
23 deletions
+262
-23
helpers.go
pkg/apis/extensions/helpers.go
+67
-0
helpers_test.go
pkg/apis/extensions/helpers_test.go
+83
-0
types.go
pkg/apis/extensions/types.go
+7
-6
defaults.go
pkg/apis/extensions/v1beta1/defaults.go
+4
-2
defaults_test.go
pkg/apis/extensions/v1beta1/defaults_test.go
+6
-2
types.go
pkg/apis/extensions/v1beta1/types.go
+38
-1
validation.go
pkg/apis/extensions/validation/validation.go
+39
-6
validation_test.go
pkg/apis/extensions/validation/validation_test.go
+6
-6
selector.go
pkg/labels/selector.go
+12
-0
No files found.
pkg/apis/extensions/helpers.go
0 → 100644
View file @
29c50cdc
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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
extensions
import
(
"fmt"
"sort"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util/sets"
)
// PodSelectorAsSelector converts the PodSelector api type into a struct that implements
// labels.Selector
func
PodSelectorAsSelector
(
ps
*
PodSelector
)
(
labels
.
Selector
,
error
)
{
if
ps
==
nil
{
return
labels
.
Nothing
(),
nil
}
if
len
(
ps
.
MatchLabels
)
+
len
(
ps
.
MatchExpressions
)
==
0
{
return
labels
.
Everything
(),
nil
}
selector
:=
labels
.
LabelSelector
{}
for
k
,
v
:=
range
ps
.
MatchLabels
{
req
,
err
:=
labels
.
NewRequirement
(
k
,
labels
.
InOperator
,
sets
.
NewString
(
v
))
if
err
!=
nil
{
return
nil
,
err
}
selector
=
append
(
selector
,
*
req
)
}
for
_
,
expr
:=
range
ps
.
MatchExpressions
{
var
op
labels
.
Operator
switch
expr
.
Operator
{
case
PodSelectorOpIn
:
op
=
labels
.
InOperator
case
PodSelectorOpNotIn
:
op
=
labels
.
NotInOperator
case
PodSelectorOpExists
:
op
=
labels
.
ExistsOperator
case
PodSelectorOpDoesNotExist
:
op
=
labels
.
DoesNotExistOperator
default
:
return
nil
,
fmt
.
Errorf
(
"%q is not a valid pod selector operator"
,
expr
.
Operator
)
}
req
,
err
:=
labels
.
NewRequirement
(
expr
.
Key
,
op
,
sets
.
NewString
(
expr
.
Values
...
))
if
err
!=
nil
{
return
nil
,
err
}
selector
=
append
(
selector
,
*
req
)
}
sort
.
Sort
(
labels
.
ByKey
(
selector
))
return
selector
,
nil
}
pkg/apis/extensions/helpers_test.go
0 → 100644
View file @
29c50cdc
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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
extensions
import
(
"reflect"
"testing"
"k8s.io/kubernetes/pkg/labels"
)
func
TestPodSelectorAsSelector
(
t
*
testing
.
T
)
{
matchLabels
:=
map
[
string
]
string
{
"foo"
:
"bar"
}
matchExpressions
:=
[]
PodSelectorRequirement
{{
Key
:
"baz"
,
Operator
:
PodSelectorOpIn
,
Values
:
[]
string
{
"qux"
,
"norf"
},
}}
mustParse
:=
func
(
s
string
)
labels
.
Selector
{
out
,
e
:=
labels
.
Parse
(
s
)
if
e
!=
nil
{
panic
(
e
)
}
return
out
}
tc
:=
[]
struct
{
in
*
PodSelector
out
labels
.
Selector
expectErr
bool
}{
{
in
:
nil
,
out
:
labels
.
Nothing
()},
{
in
:
&
PodSelector
{},
out
:
labels
.
Everything
()},
{
in
:
&
PodSelector
{
MatchLabels
:
matchLabels
},
out
:
mustParse
(
"foo in (bar)"
),
},
{
in
:
&
PodSelector
{
MatchExpressions
:
matchExpressions
},
out
:
mustParse
(
"baz in (norf,qux)"
),
},
{
in
:
&
PodSelector
{
MatchLabels
:
matchLabels
,
MatchExpressions
:
matchExpressions
},
out
:
mustParse
(
"foo in (bar),baz in (norf,qux)"
),
},
{
in
:
&
PodSelector
{
MatchExpressions
:
[]
PodSelectorRequirement
{{
Key
:
"baz"
,
Operator
:
PodSelectorOpExists
,
Values
:
[]
string
{
"qux"
,
"norf"
},
}},
},
expectErr
:
true
,
},
}
for
i
,
tc
:=
range
tc
{
out
,
err
:=
PodSelectorAsSelector
(
tc
.
in
)
if
err
==
nil
&&
tc
.
expectErr
{
t
.
Errorf
(
"[%v]expected error but got none."
,
i
)
}
if
err
!=
nil
&&
!
tc
.
expectErr
{
t
.
Errorf
(
"[%v]did not expect error but got: %v"
,
i
,
err
)
}
if
!
reflect
.
DeepEqual
(
out
,
tc
.
out
)
{
t
.
Errorf
(
"[%v]expected:
\n\t
%+v
\n
but got:
\n\t
%+v"
,
i
,
tc
.
out
,
out
)
}
}
}
pkg/apis/extensions/types.go
View file @
29c50cdc
...
...
@@ -405,7 +405,7 @@ type JobSpec struct {
Completions
*
int
`json:"completions,omitempty"`
// Selector is a label query over pods that should match the pod count.
Selector
map
[
string
]
string
`json:"selector
"`
Selector
*
PodSelector
`json:"selector,omitempty
"`
// Template is the object that describes the pod that will be created when
// executing a job.
...
...
@@ -661,7 +661,7 @@ type PodSelector struct {
MatchExpressions
[]
PodSelectorRequirement
`json:"matchExpressions,omitempty"`
}
// A pod selector requirement is a selector that contains values, a key and an operator that
// A pod selector requirement is a selector that contains values, a key
,
and an operator that
// relates the key and values.
type
PodSelectorRequirement
struct
{
// key is the label key that the selector applies to.
...
...
@@ -669,10 +669,11 @@ type PodSelectorRequirement struct {
// operator represents a key's relationship to a set of values.
// Valid operators ard In, NotIn, Exists and DoesNotExist.
Operator
PodSelectorOperator
`json:"operator"`
// values is a set of string values. If the operator is In or NotIn,
// the values set must be non-empty. This array is replaced during a
// strategic merge patch.
Values
[]
string
`json:"stringValues,omitempty"`
// values is an array of string values. If the operator is In or NotIn,
// the values array must be non-empty. If the operator is Exists or DoesNotExist,
// the values array must be empty. This array is replaced during a strategic
// merge patch.
Values
[]
string
`json:"values,omitempty"`
}
// A pod selector operator is the set of operators that can be used in a selector requirement.
...
...
pkg/apis/extensions/v1beta1/defaults.go
View file @
29c50cdc
...
...
@@ -92,8 +92,10 @@ func addDefaultingFuncs() {
labels
:=
obj
.
Spec
.
Template
.
Labels
// TODO: support templates defined elsewhere when we support them in the API
if
labels
!=
nil
{
if
len
(
obj
.
Spec
.
Selector
)
==
0
{
obj
.
Spec
.
Selector
=
labels
if
obj
.
Spec
.
Selector
==
nil
{
obj
.
Spec
.
Selector
=
&
PodSelector
{
MatchLabels
:
labels
,
}
}
if
len
(
obj
.
Labels
)
==
0
{
obj
.
Labels
=
labels
...
...
pkg/apis/extensions/v1beta1/defaults_test.go
View file @
29c50cdc
...
...
@@ -192,7 +192,9 @@ func TestSetDefaultDeployment(t *testing.T) {
func
TestSetDefaultJob
(
t
*
testing
.
T
)
{
expected
:=
&
Job
{
Spec
:
JobSpec
{
Selector
:
map
[
string
]
string
{
"job"
:
"selector"
},
Selector
:
&
PodSelector
{
MatchLabels
:
map
[
string
]
string
{
"job"
:
"selector"
},
},
Completions
:
newInt
(
1
),
Parallelism
:
newInt
(
1
),
},
...
...
@@ -201,7 +203,9 @@ func TestSetDefaultJob(t *testing.T) {
// selector set explicitly, completions and parallelism - default
{
Spec
:
JobSpec
{
Selector
:
map
[
string
]
string
{
"job"
:
"selector"
},
Selector
:
&
PodSelector
{
MatchLabels
:
map
[
string
]
string
{
"job"
:
"selector"
},
},
},
},
// selector from template labels, completions and parallelism - default
...
...
pkg/apis/extensions/v1beta1/types.go
View file @
29c50cdc
...
...
@@ -412,7 +412,7 @@ type JobSpec struct {
// Selector is a label query over pods that should match the pod count.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
Selector
map
[
string
]
string
`json:"selector,omitempty"`
Selector
*
PodSelector
`json:"selector,omitempty"`
// Template is the object that describes the pod that will be created when
// executing a job.
...
...
@@ -657,3 +657,40 @@ type ClusterAutoscalerList struct {
Items
[]
ClusterAutoscaler
`json:"items"`
}
// A pod selector is a label query over a set of pods. The result of matchLabels and
// matchExpressions are ANDed. An empty pod selector matches all objects. A null
// pod selector matches no objects.
type
PodSelector
struct
{
// matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels
// map is equivalent to an element of matchExpressions, whose key field is "key", the
// operator is "In", and the values array contains only "value". The requirements are ANDed.
MatchLabels
map
[
string
]
string
`json:"matchLabels,omitempty"`
// matchExpressions is a list of pod selector requirements. The requirements are ANDed.
MatchExpressions
[]
PodSelectorRequirement
`json:"matchExpressions,omitempty"`
}
// A pod selector requirement is a selector that contains values, a key, and an operator that
// relates the key and values.
type
PodSelectorRequirement
struct
{
// key is the label key that the selector applies to.
Key
string
`json:"key" patchStrategy:"merge" patchMergeKey:"key"`
// operator represents a key's relationship to a set of values.
// Valid operators ard In, NotIn, Exists and DoesNotExist.
Operator
PodSelectorOperator
`json:"operator"`
// values is an array of string values. If the operator is In or NotIn,
// the values array must be non-empty. If the operator is Exists or DoesNotExist,
// the values array must be empty. This array is replaced during a strategic
// merge patch.
Values
[]
string
`json:"values,omitempty"`
}
// A pod selector operator is the set of operators that can be used in a selector requirement.
type
PodSelectorOperator
string
const
(
PodSelectorOpIn
PodSelectorOperator
=
"In"
PodSelectorOpNotIn
PodSelectorOperator
=
"NotIn"
PodSelectorOpExists
PodSelectorOperator
=
"Exists"
PodSelectorOpDoesNotExist
PodSelectorOperator
=
"DoesNotExist"
)
pkg/apis/extensions/validation/validation.go
View file @
29c50cdc
...
...
@@ -345,16 +345,19 @@ func ValidateJobSpec(spec *extensions.JobSpec) errs.ValidationErrorList {
if
spec
.
Completions
!=
nil
&&
*
spec
.
Completions
<
0
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"completions"
,
spec
.
Completions
,
isNegativeErrorMsg
))
}
selector
:=
labels
.
Set
(
spec
.
Selector
)
.
AsSelector
()
if
selector
.
Empty
()
{
if
spec
.
Selector
==
nil
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldRequired
(
"selector"
))
}
else
{
allErrs
=
append
(
allErrs
,
ValidatePodSelector
(
spec
.
Selector
)
.
Prefix
(
"selector"
)
...
)
}
labels
:=
labels
.
Set
(
spec
.
Template
.
Labels
)
if
!
selector
.
Matches
(
labels
)
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"template.labels"
,
spec
.
Template
.
Labels
,
"selector does not match template"
))
if
selector
,
err
:=
extensions
.
PodSelectorAsSelector
(
spec
.
Selector
);
err
==
nil
{
labels
:=
labels
.
Set
(
spec
.
Template
.
Labels
)
if
!
selector
.
Matches
(
labels
)
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"template.metadata.labels"
,
spec
.
Template
.
Labels
,
"selector does not match template"
))
}
}
allErrs
=
append
(
allErrs
,
apivalidation
.
ValidatePodTemplateSpec
(
&
spec
.
Template
)
.
Prefix
(
"template"
)
...
)
if
spec
.
Template
.
Spec
.
RestartPolicy
!=
api
.
RestartPolicyOnFailure
&&
spec
.
Template
.
Spec
.
RestartPolicy
!=
api
.
RestartPolicyNever
{
...
...
@@ -568,3 +571,33 @@ func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) errs.Va
allErrs
=
append
(
allErrs
,
validateClusterAutoscalerSpec
(
autoscaler
.
Spec
)
...
)
return
allErrs
}
func
ValidatePodSelector
(
ps
*
extensions
.
PodSelector
)
errs
.
ValidationErrorList
{
allErrs
:=
errs
.
ValidationErrorList
{}
if
ps
==
nil
{
return
allErrs
}
allErrs
=
append
(
allErrs
,
apivalidation
.
ValidateLabels
(
ps
.
MatchLabels
,
"matchLabels"
)
...
)
for
i
,
expr
:=
range
ps
.
MatchExpressions
{
allErrs
=
append
(
allErrs
,
ValidatePodSelectorRequirement
(
expr
)
.
Prefix
(
fmt
.
Sprintf
(
"matchExpressions.[%v]"
,
i
))
...
)
}
return
allErrs
}
func
ValidatePodSelectorRequirement
(
sr
extensions
.
PodSelectorRequirement
)
errs
.
ValidationErrorList
{
allErrs
:=
errs
.
ValidationErrorList
{}
switch
sr
.
Operator
{
case
extensions
.
PodSelectorOpIn
,
extensions
.
PodSelectorOpNotIn
:
if
len
(
sr
.
Values
)
==
0
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"values"
,
sr
.
Values
,
"must be non-empty when operator is In or NotIn"
))
}
case
extensions
.
PodSelectorOpExists
,
extensions
.
PodSelectorOpDoesNotExist
:
if
len
(
sr
.
Values
)
>
0
{
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"values"
,
sr
.
Values
,
"must be empty when operator is Exists or DoesNotExist"
))
}
default
:
allErrs
=
append
(
allErrs
,
errs
.
NewFieldInvalid
(
"operator"
,
sr
.
Operator
,
"not a valid pod selector operator"
))
}
allErrs
=
append
(
allErrs
,
apivalidation
.
ValidateLabelName
(
sr
.
Key
,
"key"
)
...
)
return
allErrs
}
pkg/apis/extensions/validation/validation_test.go
View file @
29c50cdc
...
...
@@ -192,7 +192,6 @@ func TestValidateDaemonSetStatusUpdate(t *testing.T) {
t
.
Errorf
(
"expected failure: %s"
,
testName
)
}
}
}
func
TestValidateDaemonSetUpdate
(
t
*
testing
.
T
)
{
...
...
@@ -725,10 +724,12 @@ func TestValidateDeployment(t *testing.T) {
}
func
TestValidateJob
(
t
*
testing
.
T
)
{
validSelector
:=
map
[
string
]
string
{
"a"
:
"b"
}
validSelector
:=
&
extensions
.
PodSelector
{
MatchLabels
:
map
[
string
]
string
{
"a"
:
"b"
},
}
validPodTemplateSpec
:=
api
.
PodTemplateSpec
{
ObjectMeta
:
api
.
ObjectMeta
{
Labels
:
validSelector
,
Labels
:
validSelector
.
MatchLabels
,
},
Spec
:
api
.
PodSpec
{
RestartPolicy
:
api
.
RestartPolicyOnFailure
,
...
...
@@ -783,11 +784,10 @@ func TestValidateJob(t *testing.T) {
Namespace
:
api
.
NamespaceDefault
,
},
Spec
:
extensions
.
JobSpec
{
Selector
:
map
[
string
]
string
{},
Template
:
validPodTemplateSpec
,
},
},
"spec.template.
labels:
selector does not match template"
:
{
"spec.template.
metadata.labels: invalid value 'map[y:z]', Details:
selector does not match template"
:
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"myjob"
,
Namespace
:
api
.
NamespaceDefault
,
...
...
@@ -815,7 +815,7 @@ func TestValidateJob(t *testing.T) {
Selector
:
validSelector
,
Template
:
api
.
PodTemplateSpec
{
ObjectMeta
:
api
.
ObjectMeta
{
Labels
:
validSelector
,
Labels
:
validSelector
.
MatchLabels
,
},
Spec
:
api
.
PodSpec
{
RestartPolicy
:
api
.
RestartPolicyAlways
,
...
...
pkg/labels/selector.go
View file @
29c50cdc
...
...
@@ -47,6 +47,18 @@ func Everything() Selector {
return
LabelSelector
{}
}
type
nothingSelector
struct
{}
func
(
n
nothingSelector
)
Matches
(
_
Labels
)
bool
{
return
false
}
func
(
n
nothingSelector
)
Empty
()
bool
{
return
false
}
func
(
n
nothingSelector
)
String
()
string
{
return
"<null>"
}
func
(
n
nothingSelector
)
Add
(
_
string
,
_
Operator
,
_
[]
string
)
Selector
{
return
n
}
// Nothing returns a selector that matches no labels
func
Nothing
()
Selector
{
return
nothingSelector
{}
}
// Operator represents a key's relationship
// to a set of values in a Requirement.
type
Operator
string
...
...
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