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
dbab67aa
Commit
dbab67aa
authored
Mar 02, 2017
by
Michail Kargakis
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
controller: statefulsets respect observed generation
parent
113cd7da
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
35 additions
and
11 deletions
+35
-11
test-cmd-util.sh
hack/make-rules/test-cmd-util.sh
+3
-0
stateful_pod_control.go
pkg/controller/statefulset/stateful_pod_control.go
+5
-4
stateful_pod_control_test.go
pkg/controller/statefulset/stateful_pod_control_test.go
+23
-4
stateful_set_control.go
pkg/controller/statefulset/stateful_set_control.go
+2
-2
stateful_set_control_test.go
pkg/controller/statefulset/stateful_set_control_test.go
+2
-1
No files found.
hack/make-rules/test-cmd-util.sh
View file @
dbab67aa
...
@@ -2747,6 +2747,7 @@ runTests() {
...
@@ -2747,6 +2747,7 @@ runTests() {
hpa_max_field
=
".spec.maxReplicas"
hpa_max_field
=
".spec.maxReplicas"
hpa_cpu_field
=
".spec.targetCPUUtilizationPercentage"
hpa_cpu_field
=
".spec.targetCPUUtilizationPercentage"
statefulset_replicas_field
=
".spec.replicas"
statefulset_replicas_field
=
".spec.replicas"
statefulset_observed_generation
=
".status.observedGeneration"
job_parallelism_field
=
".spec.parallelism"
job_parallelism_field
=
".spec.parallelism"
deployment_replicas
=
".spec.replicas"
deployment_replicas
=
".spec.replicas"
secret_data
=
".data"
secret_data
=
".data"
...
@@ -3180,10 +3181,12 @@ runTests() {
...
@@ -3180,10 +3181,12 @@ runTests() {
### Scale statefulset test with current-replicas and replicas
### Scale statefulset test with current-replicas and replicas
# Pre-condition: 0 replicas
# Pre-condition: 0 replicas
kube::test::get_object_assert
'statefulset nginx'
"{{
$statefulset_replicas_field
}}"
'0'
kube::test::get_object_assert
'statefulset nginx'
"{{
$statefulset_replicas_field
}}"
'0'
kube::test::wait_object_assert
'statefulset nginx'
"{{
$statefulset_observed_generation
}}"
'1'
# Command: Scale up
# Command: Scale up
kubectl scale
--current-replicas
=
0
--replicas
=
1 statefulset nginx
"
${
kube_flags
[@]
}
"
kubectl scale
--current-replicas
=
0
--replicas
=
1 statefulset nginx
"
${
kube_flags
[@]
}
"
# Post-condition: 1 replica, named nginx-0
# Post-condition: 1 replica, named nginx-0
kube::test::get_object_assert
'statefulset nginx'
"{{
$statefulset_replicas_field
}}"
'1'
kube::test::get_object_assert
'statefulset nginx'
"{{
$statefulset_replicas_field
}}"
'1'
kube::test::wait_object_assert
'statefulset nginx'
"{{
$statefulset_observed_generation
}}"
'2'
# Typically we'd wait and confirm that N>1 replicas are up, but this framework
# Typically we'd wait and confirm that N>1 replicas are up, but this framework
# doesn't start the scheduler, so pet-0 will block all others.
# doesn't start the scheduler, so pet-0 will block all others.
# TODO: test robust scaling in an e2e.
# TODO: test robust scaling in an e2e.
...
...
pkg/controller/statefulset/stateful_pod_control.go
View file @
dbab67aa
...
@@ -49,10 +49,10 @@ type StatefulPodControlInterface interface {
...
@@ -49,10 +49,10 @@ type StatefulPodControlInterface interface {
// DeleteStatefulPod deletes a Pod in a StatefulSet. The pods PVCs are not deleted. If the delete is successful,
// DeleteStatefulPod deletes a Pod in a StatefulSet. The pods PVCs are not deleted. If the delete is successful,
// the returned error is nil.
// the returned error is nil.
DeleteStatefulPod
(
set
*
apps
.
StatefulSet
,
pod
*
v1
.
Pod
)
error
DeleteStatefulPod
(
set
*
apps
.
StatefulSet
,
pod
*
v1
.
Pod
)
error
// UpdateStatefulSetStatus
Updates the Status.Replica
s of a StatefulSet. set is an in-out parameter, and any
// UpdateStatefulSetStatus
updates the statu
s of a StatefulSet. set is an in-out parameter, and any
// updates made to the set are made visible as mutations to the parameter. If the method is successful, the
// updates made to the set are made visible as mutations to the parameter. If the method is successful, the
// returned error is nil, and set has its
Status.Replicas field set to replicas
.
// returned error is nil, and set has its
status updated
.
UpdateStatefulSet
Replicas
(
set
*
apps
.
StatefulSet
,
replicas
int32
)
error
UpdateStatefulSet
Status
(
set
*
apps
.
StatefulSet
,
replicas
int32
,
generation
int64
)
error
}
}
func
NewRealStatefulPodControl
(
func
NewRealStatefulPodControl
(
...
@@ -150,9 +150,10 @@ func (spc *realStatefulPodControl) DeleteStatefulPod(set *apps.StatefulSet, pod
...
@@ -150,9 +150,10 @@ func (spc *realStatefulPodControl) DeleteStatefulPod(set *apps.StatefulSet, pod
return
err
return
err
}
}
func
(
spc
*
realStatefulPodControl
)
UpdateStatefulSet
Replicas
(
set
*
apps
.
StatefulSet
,
replicas
int32
)
error
{
func
(
spc
*
realStatefulPodControl
)
UpdateStatefulSet
Status
(
set
*
apps
.
StatefulSet
,
replicas
int32
,
generation
int64
)
error
{
return
retry
.
RetryOnConflict
(
retry
.
DefaultBackoff
,
func
()
error
{
return
retry
.
RetryOnConflict
(
retry
.
DefaultBackoff
,
func
()
error
{
set
.
Status
.
Replicas
=
replicas
set
.
Status
.
Replicas
=
replicas
set
.
Status
.
ObservedGeneration
=
&
generation
_
,
err
:=
spc
.
client
.
Apps
()
.
StatefulSets
(
set
.
Namespace
)
.
UpdateStatus
(
set
)
_
,
err
:=
spc
.
client
.
Apps
()
.
StatefulSets
(
set
.
Namespace
)
.
UpdateStatus
(
set
)
if
err
==
nil
{
if
err
==
nil
{
return
nil
return
nil
...
...
pkg/controller/statefulset/stateful_pod_control_test.go
View file @
dbab67aa
...
@@ -30,6 +30,7 @@ import (
...
@@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/api/v1"
podapi
"k8s.io/kubernetes/pkg/api/v1/pod"
podapi
"k8s.io/kubernetes/pkg/api/v1/pod"
apps
"k8s.io/kubernetes/pkg/apis/apps/v1beta1"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
"k8s.io/kubernetes/pkg/client/clientset_generated/clientset/fake"
appslisters
"k8s.io/kubernetes/pkg/client/listers/apps/v1beta1"
appslisters
"k8s.io/kubernetes/pkg/client/listers/apps/v1beta1"
corelisters
"k8s.io/kubernetes/pkg/client/listers/core/v1"
corelisters
"k8s.io/kubernetes/pkg/client/listers/core/v1"
...
@@ -470,7 +471,7 @@ func TestStatefulPodControlUpdatesSetStatus(t *testing.T) {
...
@@ -470,7 +471,7 @@ func TestStatefulPodControlUpdatesSetStatus(t *testing.T) {
update
:=
action
.
(
core
.
UpdateAction
)
update
:=
action
.
(
core
.
UpdateAction
)
return
true
,
update
.
GetObject
(),
nil
return
true
,
update
.
GetObject
(),
nil
})
})
if
err
:=
control
.
UpdateStatefulSet
Replicas
(
set
,
2
);
err
!=
nil
{
if
err
:=
control
.
UpdateStatefulSet
Status
(
set
,
2
,
1
);
err
!=
nil
{
t
.
Errorf
(
"Error returned on successful status update: %s"
,
err
)
t
.
Errorf
(
"Error returned on successful status update: %s"
,
err
)
}
}
if
set
.
Status
.
Replicas
!=
2
{
if
set
.
Status
.
Replicas
!=
2
{
...
@@ -482,6 +483,24 @@ func TestStatefulPodControlUpdatesSetStatus(t *testing.T) {
...
@@ -482,6 +483,24 @@ func TestStatefulPodControlUpdatesSetStatus(t *testing.T) {
}
}
}
}
func
TestStatefulPodControlUpdatesObservedGeneration
(
t
*
testing
.
T
)
{
recorder
:=
record
.
NewFakeRecorder
(
10
)
set
:=
newStatefulSet
(
3
)
fakeClient
:=
&
fake
.
Clientset
{}
control
:=
NewRealStatefulPodControl
(
fakeClient
,
nil
,
nil
,
nil
,
recorder
)
fakeClient
.
AddReactor
(
"update"
,
"statefulsets"
,
func
(
action
core
.
Action
)
(
bool
,
runtime
.
Object
,
error
)
{
update
:=
action
.
(
core
.
UpdateAction
)
sts
:=
update
.
GetObject
()
.
(
*
apps
.
StatefulSet
)
if
sts
.
Status
.
ObservedGeneration
==
nil
||
*
sts
.
Status
.
ObservedGeneration
!=
int64
(
3
)
{
t
.
Errorf
(
"expected observedGeneration to be synced with generation for statefulset %q"
,
sts
.
Name
)
}
return
true
,
sts
,
nil
})
if
err
:=
control
.
UpdateStatefulSetStatus
(
set
,
2
,
3
);
err
!=
nil
{
t
.
Errorf
(
"Error returned on successful status update: %s"
,
err
)
}
}
func
TestStatefulPodControlUpdateReplicasFailure
(
t
*
testing
.
T
)
{
func
TestStatefulPodControlUpdateReplicasFailure
(
t
*
testing
.
T
)
{
recorder
:=
record
.
NewFakeRecorder
(
10
)
recorder
:=
record
.
NewFakeRecorder
(
10
)
set
:=
newStatefulSet
(
3
)
set
:=
newStatefulSet
(
3
)
...
@@ -493,7 +512,7 @@ func TestStatefulPodControlUpdateReplicasFailure(t *testing.T) {
...
@@ -493,7 +512,7 @@ func TestStatefulPodControlUpdateReplicasFailure(t *testing.T) {
fakeClient
.
AddReactor
(
"update"
,
"statefulsets"
,
func
(
action
core
.
Action
)
(
bool
,
runtime
.
Object
,
error
)
{
fakeClient
.
AddReactor
(
"update"
,
"statefulsets"
,
func
(
action
core
.
Action
)
(
bool
,
runtime
.
Object
,
error
)
{
return
true
,
nil
,
apierrors
.
NewInternalError
(
errors
.
New
(
"API server down"
))
return
true
,
nil
,
apierrors
.
NewInternalError
(
errors
.
New
(
"API server down"
))
})
})
if
err
:=
control
.
UpdateStatefulSet
Replicas
(
set
,
2
);
err
==
nil
{
if
err
:=
control
.
UpdateStatefulSet
Status
(
set
,
2
,
1
);
err
==
nil
{
t
.
Error
(
"Failed update did not return error"
)
t
.
Error
(
"Failed update did not return error"
)
}
}
events
:=
collectEvents
(
recorder
.
Events
)
events
:=
collectEvents
(
recorder
.
Events
)
...
@@ -520,7 +539,7 @@ func TestStatefulPodControlUpdateReplicasConflict(t *testing.T) {
...
@@ -520,7 +539,7 @@ func TestStatefulPodControlUpdateReplicasConflict(t *testing.T) {
return
true
,
update
.
GetObject
(),
nil
return
true
,
update
.
GetObject
(),
nil
}
}
})
})
if
err
:=
control
.
UpdateStatefulSet
Replicas
(
set
,
2
);
err
!=
nil
{
if
err
:=
control
.
UpdateStatefulSet
Status
(
set
,
2
,
1
);
err
!=
nil
{
t
.
Errorf
(
"UpdateStatefulSetStatus returned an error: %s"
,
err
)
t
.
Errorf
(
"UpdateStatefulSetStatus returned an error: %s"
,
err
)
}
}
if
set
.
Status
.
Replicas
!=
2
{
if
set
.
Status
.
Replicas
!=
2
{
...
@@ -544,7 +563,7 @@ func TestStatefulPodControlUpdateReplicasConflictFailure(t *testing.T) {
...
@@ -544,7 +563,7 @@ func TestStatefulPodControlUpdateReplicasConflictFailure(t *testing.T) {
update
:=
action
.
(
core
.
UpdateAction
)
update
:=
action
.
(
core
.
UpdateAction
)
return
true
,
update
.
GetObject
(),
apierrors
.
NewConflict
(
action
.
GetResource
()
.
GroupResource
(),
set
.
Name
,
errors
.
New
(
"Object already exists"
))
return
true
,
update
.
GetObject
(),
apierrors
.
NewConflict
(
action
.
GetResource
()
.
GroupResource
(),
set
.
Name
,
errors
.
New
(
"Object already exists"
))
})
})
if
err
:=
control
.
UpdateStatefulSet
Replicas
(
set
,
2
);
err
==
nil
{
if
err
:=
control
.
UpdateStatefulSet
Status
(
set
,
2
,
1
);
err
==
nil
{
t
.
Error
(
"UpdateStatefulSetStatus failed to return an error on get failure"
)
t
.
Error
(
"UpdateStatefulSetStatus failed to return an error on get failure"
)
}
}
events
:=
collectEvents
(
recorder
.
Events
)
events
:=
collectEvents
(
recorder
.
Events
)
...
...
pkg/controller/statefulset/stateful_set_control.go
View file @
dbab67aa
...
@@ -99,14 +99,14 @@ func (ssc *defaultStatefulSetControl) UpdateStatefulSet(set *apps.StatefulSet, p
...
@@ -99,14 +99,14 @@ func (ssc *defaultStatefulSetControl) UpdateStatefulSet(set *apps.StatefulSet, p
sort
.
Sort
(
ascendingOrdinal
(
condemned
))
sort
.
Sort
(
ascendingOrdinal
(
condemned
))
// if the current number of replicas has changed update the statefulSets replicas
// if the current number of replicas has changed update the statefulSets replicas
if
set
.
Status
.
Replicas
!=
int32
(
ready
)
{
if
set
.
Status
.
Replicas
!=
int32
(
ready
)
||
set
.
Status
.
ObservedGeneration
==
nil
||
set
.
Generation
>
*
set
.
Status
.
ObservedGeneration
{
obj
,
err
:=
api
.
Scheme
.
Copy
(
set
)
obj
,
err
:=
api
.
Scheme
.
Copy
(
set
)
if
err
!=
nil
{
if
err
!=
nil
{
return
fmt
.
Errorf
(
"unable to copy set: %v"
,
err
)
return
fmt
.
Errorf
(
"unable to copy set: %v"
,
err
)
}
}
set
=
obj
.
(
*
apps
.
StatefulSet
)
set
=
obj
.
(
*
apps
.
StatefulSet
)
if
err
:=
ssc
.
podControl
.
UpdateStatefulSet
Replicas
(
set
,
int32
(
ready
)
);
err
!=
nil
{
if
err
:=
ssc
.
podControl
.
UpdateStatefulSet
Status
(
set
,
int32
(
ready
),
set
.
Generation
);
err
!=
nil
{
return
err
return
err
}
}
}
}
...
...
pkg/controller/statefulset/stateful_set_control_test.go
View file @
dbab67aa
...
@@ -769,13 +769,14 @@ func (spc *fakeStatefulPodControl) DeleteStatefulPod(set *apps.StatefulSet, pod
...
@@ -769,13 +769,14 @@ func (spc *fakeStatefulPodControl) DeleteStatefulPod(set *apps.StatefulSet, pod
return
nil
return
nil
}
}
func
(
spc
*
fakeStatefulPodControl
)
UpdateStatefulSet
Replicas
(
set
*
apps
.
StatefulSet
,
replicas
int32
)
error
{
func
(
spc
*
fakeStatefulPodControl
)
UpdateStatefulSet
Status
(
set
*
apps
.
StatefulSet
,
replicas
int32
,
generation
int64
)
error
{
defer
spc
.
updateStatusTracker
.
inc
()
defer
spc
.
updateStatusTracker
.
inc
()
if
spc
.
updateStatusTracker
.
errorReady
()
{
if
spc
.
updateStatusTracker
.
errorReady
()
{
defer
spc
.
updateStatusTracker
.
reset
()
defer
spc
.
updateStatusTracker
.
reset
()
return
spc
.
updateStatusTracker
.
err
return
spc
.
updateStatusTracker
.
err
}
}
set
.
Status
.
Replicas
=
replicas
set
.
Status
.
Replicas
=
replicas
set
.
Status
.
ObservedGeneration
=
&
generation
spc
.
setsIndexer
.
Update
(
set
)
spc
.
setsIndexer
.
Update
(
set
)
return
nil
return
nil
}
}
...
...
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