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
7e50fa6d
Commit
7e50fa6d
authored
Feb 23, 2016
by
nikhiljindal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update DeploymentReaper.Stop to use ObservedGeneration to remove race condition
parent
9c1d8bf9
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
34 additions
and
52 deletions
+34
-52
stop.go
pkg/kubectl/stop.go
+11
-34
stop_test.go
pkg/kubectl/stop_test.go
+4
-6
deployment.go
pkg/util/deployment/deployment.go
+13
-0
deployment.go
test/e2e/deployment.go
+2
-2
util.go
test/e2e/util.go
+4
-10
No files found.
pkg/kubectl/stop.go
View file @
7e50fa6d
...
@@ -30,6 +30,7 @@ import (
...
@@ -30,6 +30,7 @@ import (
client
"k8s.io/kubernetes/pkg/client/unversioned"
client
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util"
deploymentutil
"k8s.io/kubernetes/pkg/util/deployment"
utilerrors
"k8s.io/kubernetes/pkg/util/errors"
utilerrors
"k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/wait"
"k8s.io/kubernetes/pkg/util/wait"
)
)
...
@@ -368,52 +369,30 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
...
@@ -368,52 +369,30 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
zero
:=
0
zero
:=
0
d
.
Spec
.
RevisionHistoryLimit
=
&
zero
d
.
Spec
.
RevisionHistoryLimit
=
&
zero
d
.
Spec
.
Replicas
=
0
d
.
Spec
.
Replicas
=
0
// TODO: un-pausing should not be necessary, remove when this is fixed:
d
.
Spec
.
Paused
=
true
// https://github.com/kubernetes/kubernetes/issues/20966
// Instead deployment should be Paused at this point and not at next TODO.
d
.
Spec
.
Paused
=
false
})
})
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
// wait for total no of pods drop to 0
// Use observedGeneration to determine if the deployment controller noticed the pause.
if
err
:=
wait
.
Poll
(
reaper
.
pollInterval
,
reaper
.
timeout
,
func
()
(
bool
,
error
)
{
if
err
:=
deploymentutil
.
WaitForObservedDeployment
(
func
()
(
*
extensions
.
Deployment
,
error
)
{
curr
,
err
:=
deployments
.
Get
(
name
)
return
deployments
.
Get
(
name
)
// if deployment was not found it must have been deleted, error out
},
deployment
.
Generation
,
10
*
time
.
Millisecond
,
1
*
time
.
Minute
);
err
!=
nil
{
if
err
!=
nil
&&
errors
.
IsNotFound
(
err
)
{
return
false
,
err
}
// if other errors happen, retry
if
err
!=
nil
{
return
false
,
nil
}
// check if deployment wasn't recreated with the same name
// TODO use generations when deployment will have them
if
curr
.
UID
!=
deployment
.
UID
{
return
false
,
errors
.
NewNotFound
(
extensions
.
Resource
(
"Deployment"
),
name
)
}
return
curr
.
Status
.
Replicas
==
0
,
nil
});
err
!=
nil
{
return
err
return
err
}
}
// TODO: When deployments will allow running cleanup policy while being
// Delete deployment.
// paused, move pausing to above update operation. Without it, we need to
if
err
:=
deployments
.
Delete
(
name
,
gracePeriod
);
err
!=
nil
{
// pause deployment before stopping RSs, to prevent creating new RSs.
// See https://github.com/kubernetes/kubernetes/issues/20966
deployment
,
err
=
reaper
.
updateDeploymentWithRetries
(
namespace
,
name
,
func
(
d
*
extensions
.
Deployment
)
{
d
.
Spec
.
Paused
=
true
})
if
err
!=
nil
{
return
err
return
err
}
}
//
remove remaining RSs
//
Stop all replica sets.
selector
,
err
:=
unversioned
.
LabelSelectorAsSelector
(
deployment
.
Spec
.
Selector
)
selector
,
err
:=
unversioned
.
LabelSelectorAsSelector
(
deployment
.
Spec
.
Selector
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
options
:=
api
.
ListOptions
{
LabelSelector
:
selector
}
options
:=
api
.
ListOptions
{
LabelSelector
:
selector
}
rsList
,
err
:=
replicaSets
.
List
(
options
)
rsList
,
err
:=
replicaSets
.
List
(
options
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -430,9 +409,7 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
...
@@ -430,9 +409,7 @@ func (reaper *DeploymentReaper) Stop(namespace, name string, timeout time.Durati
if
len
(
errList
)
>
0
{
if
len
(
errList
)
>
0
{
return
utilerrors
.
NewAggregate
(
errList
)
return
utilerrors
.
NewAggregate
(
errList
)
}
}
return
nil
// and finally deployment
return
deployments
.
Delete
(
name
,
gracePeriod
)
}
}
type
updateDeploymentFunc
func
(
d
*
extensions
.
Deployment
)
type
updateDeploymentFunc
func
(
d
*
extensions
.
Deployment
)
...
...
pkg/kubectl/stop_test.go
View file @
7e50fa6d
...
@@ -538,8 +538,7 @@ func TestDeploymentStop(t *testing.T) {
...
@@ -538,8 +538,7 @@ func TestDeploymentStop(t *testing.T) {
},
},
StopError
:
nil
,
StopError
:
nil
,
ExpectedActions
:
[]
string
{
"get:deployments"
,
"update:deployments"
,
ExpectedActions
:
[]
string
{
"get:deployments"
,
"update:deployments"
,
"get:deployments"
,
"get:deployments"
,
"update:deployments"
,
"get:deployments"
,
"delete:deployments"
,
"list:replicasets"
},
"list:replicasets"
,
"delete:deployments"
},
},
},
{
{
Name
:
"Deployment with single replicaset"
,
Name
:
"Deployment with single replicaset"
,
...
@@ -561,10 +560,9 @@ func TestDeploymentStop(t *testing.T) {
...
@@ -561,10 +560,9 @@ func TestDeploymentStop(t *testing.T) {
},
},
StopError
:
nil
,
StopError
:
nil
,
ExpectedActions
:
[]
string
{
"get:deployments"
,
"update:deployments"
,
ExpectedActions
:
[]
string
{
"get:deployments"
,
"update:deployments"
,
"get:deployments"
,
"get:deployments"
,
"update:deployments"
,
"get:deployments"
,
"delete:deployments"
,
"list:replicasets"
,
"list:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"update:replicasets"
,
"update:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"get:replicasets"
,
"delete:replicasets"
},
"delete:replicasets"
,
"delete:deployments"
},
},
},
}
}
...
...
pkg/util/deployment/deployment.go
View file @
7e50fa6d
...
@@ -427,3 +427,16 @@ func NewRSNewReplicas(deployment *extensions.Deployment, allRSs []*extensions.Re
...
@@ -427,3 +427,16 @@ func NewRSNewReplicas(deployment *extensions.Deployment, allRSs []*extensions.Re
return
0
,
fmt
.
Errorf
(
"deployment type %v isn't supported"
,
deployment
.
Spec
.
Strategy
.
Type
)
return
0
,
fmt
.
Errorf
(
"deployment type %v isn't supported"
,
deployment
.
Spec
.
Strategy
.
Type
)
}
}
}
}
// Polls for deployment to be updated so that deployment.Status.ObservedGeneration >= desiredGeneration.
// Returns error if polling timesout.
func
WaitForObservedDeployment
(
getDeploymentFunc
func
()
(
*
extensions
.
Deployment
,
error
),
desiredGeneration
int64
,
interval
,
timeout
time
.
Duration
)
error
{
// TODO: This should take clientset.Interface when all code is updated to use clientset. Keeping it this way allows the function to be used by callers who have client.Interface.
return
wait
.
Poll
(
interval
,
timeout
,
func
()
(
bool
,
error
)
{
deployment
,
err
:=
getDeploymentFunc
()
if
err
!=
nil
{
return
false
,
err
}
return
deployment
.
Status
.
ObservedGeneration
>=
desiredGeneration
,
nil
})
}
test/e2e/deployment.go
View file @
7e50fa6d
...
@@ -543,7 +543,7 @@ func testPausedDeployment(f *Framework) {
...
@@ -543,7 +543,7 @@ func testPausedDeployment(f *Framework) {
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
// Use observedGeneration to determine if the controller noticed the resume.
// Use observedGeneration to determine if the controller noticed the resume.
err
=
waitForObservedDeployment
(
c
,
ns
,
deploymentName
)
err
=
waitForObservedDeployment
(
c
,
ns
,
deploymentName
,
deployment
.
Generation
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
selector
,
err
:=
unversioned
.
LabelSelectorAsSelector
(
deployment
.
Spec
.
Selector
)
selector
,
err
:=
unversioned
.
LabelSelectorAsSelector
(
deployment
.
Spec
.
Selector
)
...
@@ -570,7 +570,7 @@ func testPausedDeployment(f *Framework) {
...
@@ -570,7 +570,7 @@ func testPausedDeployment(f *Framework) {
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
// Use observedGeneration to determine if the controller noticed the pause.
// Use observedGeneration to determine if the controller noticed the pause.
err
=
waitForObservedDeployment
(
c
,
ns
,
deploymentName
)
err
=
waitForObservedDeployment
(
c
,
ns
,
deploymentName
,
deployment
.
Generation
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
newRS
,
err
:=
deploymentutil
.
GetNewReplicaSet
(
*
deployment
,
c
)
newRS
,
err
:=
deploymentutil
.
GetNewReplicaSet
(
*
deployment
,
c
)
...
...
test/e2e/util.go
View file @
7e50fa6d
...
@@ -2224,16 +2224,6 @@ func waitForDeploymentOldRSsNum(c *clientset.Clientset, ns, deploymentName strin
...
@@ -2224,16 +2224,6 @@ func waitForDeploymentOldRSsNum(c *clientset.Clientset, ns, deploymentName strin
})
})
}
}
func
waitForObservedDeployment
(
c
*
clientset
.
Clientset
,
ns
,
deploymentName
string
)
error
{
return
wait
.
Poll
(
poll
,
1
*
time
.
Minute
,
func
()
(
bool
,
error
)
{
deployment
,
err
:=
c
.
Extensions
()
.
Deployments
(
ns
)
.
Get
(
deploymentName
)
if
err
!=
nil
{
return
false
,
err
}
return
deployment
.
Generation
==
deployment
.
Status
.
ObservedGeneration
,
nil
})
}
func
logReplicaSetsOfDeployment
(
deployment
*
extensions
.
Deployment
,
allOldRSs
[]
*
extensions
.
ReplicaSet
,
newRS
*
extensions
.
ReplicaSet
)
{
func
logReplicaSetsOfDeployment
(
deployment
*
extensions
.
Deployment
,
allOldRSs
[]
*
extensions
.
ReplicaSet
,
newRS
*
extensions
.
ReplicaSet
)
{
Logf
(
"Deployment = %+v"
,
deployment
)
Logf
(
"Deployment = %+v"
,
deployment
)
for
i
:=
range
allOldRSs
{
for
i
:=
range
allOldRSs
{
...
@@ -2242,6 +2232,10 @@ func logReplicaSetsOfDeployment(deployment *extensions.Deployment, allOldRSs []*
...
@@ -2242,6 +2232,10 @@ func logReplicaSetsOfDeployment(deployment *extensions.Deployment, allOldRSs []*
Logf
(
"New ReplicaSet of deployment %s: %+v"
,
deployment
.
Name
,
newRS
)
Logf
(
"New ReplicaSet of deployment %s: %+v"
,
deployment
.
Name
,
newRS
)
}
}
func
waitForObservedDeployment
(
c
*
clientset
.
Clientset
,
ns
,
deploymentName
string
,
desiredGeneration
int64
)
error
{
return
deploymentutil
.
WaitForObservedDeployment
(
func
()
(
*
extensions
.
Deployment
,
error
)
{
return
c
.
Extensions
()
.
Deployments
(
ns
)
.
Get
(
deploymentName
)
},
desiredGeneration
,
poll
,
1
*
time
.
Minute
)
}
func
logPodsOfReplicaSets
(
c
clientset
.
Interface
,
rss
[]
*
extensions
.
ReplicaSet
,
minReadySeconds
int
)
{
func
logPodsOfReplicaSets
(
c
clientset
.
Interface
,
rss
[]
*
extensions
.
ReplicaSet
,
minReadySeconds
int
)
{
allPods
,
err
:=
deploymentutil
.
GetPodsForReplicaSets
(
c
,
rss
)
allPods
,
err
:=
deploymentutil
.
GetPodsForReplicaSets
(
c
,
rss
)
if
err
==
nil
{
if
err
==
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