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
d25af7bb
Commit
d25af7bb
authored
Nov 01, 2017
by
Jun Xiang Tee
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor replicaset sync call tree
parent
82184d8e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
502 additions
and
1 deletion
+502
-1
BUILD
pkg/controller/replicaset/BUILD
+4
-1
replica_set.go
pkg/controller/replicaset/replica_set.go
+0
-0
replica_set_test.go
pkg/controller/replicaset/replica_set_test.go
+252
-0
replica_set_utils_test.go
pkg/controller/replicaset/replica_set_utils_test.go
+246
-0
No files found.
pkg/controller/replicaset/BUILD
View file @
d25af7bb
...
...
@@ -43,7 +43,10 @@ go_library(
go_test(
name = "go_default_test",
srcs = ["replica_set_test.go"],
srcs = [
"replica_set_test.go",
"replica_set_utils_test.go",
],
importpath = "k8s.io/kubernetes/pkg/controller/replicaset",
library = ":go_default_library",
deps = [
...
...
pkg/controller/replicaset/replica_set.go
View file @
d25af7bb
This diff is collapsed.
Click to expand it.
pkg/controller/replicaset/replica_set_test.go
View file @
d25af7bb
...
...
@@ -26,6 +26,7 @@ import (
"net/url"
"reflect"
"strings"
"sync"
"testing"
"time"
...
...
@@ -1373,3 +1374,254 @@ func TestRemoveCondition(t *testing.T) {
}
}
}
func
TestSlowStartBatch
(
t
*
testing
.
T
)
{
fakeErr
:=
fmt
.
Errorf
(
"fake error"
)
callCnt
:=
0
callLimit
:=
0
var
lock
sync
.
Mutex
fn
:=
func
()
error
{
lock
.
Lock
()
defer
lock
.
Unlock
()
callCnt
++
if
callCnt
>
callLimit
{
return
fakeErr
}
return
nil
}
tests
:=
[]
struct
{
name
string
count
int
callLimit
int
fn
func
()
error
expectedSuccesses
int
expectedErr
error
expectedCallCnt
int
}{
{
name
:
"callLimit = 0 (all fail)"
,
count
:
10
,
callLimit
:
0
,
fn
:
fn
,
expectedSuccesses
:
0
,
expectedErr
:
fakeErr
,
expectedCallCnt
:
1
,
// 1(first batch): function will be called at least once
},
{
name
:
"callLimit = count (all succeed)"
,
count
:
10
,
callLimit
:
10
,
fn
:
fn
,
expectedSuccesses
:
10
,
expectedErr
:
nil
,
expectedCallCnt
:
10
,
// 1(first batch) + 2(2nd batch) + 4(3rd batch) + 3(4th batch) = 10
},
{
name
:
"callLimit < count (some succeed)"
,
count
:
10
,
callLimit
:
5
,
fn
:
fn
,
expectedSuccesses
:
5
,
expectedErr
:
fakeErr
,
expectedCallCnt
:
7
,
// 1(first batch) + 2(2nd batch) + 4(3rd batch) = 7
},
}
for
_
,
test
:=
range
tests
{
callCnt
=
0
callLimit
=
test
.
callLimit
successes
,
err
:=
slowStartBatch
(
test
.
count
,
1
,
test
.
fn
)
if
successes
!=
test
.
expectedSuccesses
{
t
.
Errorf
(
"%s: unexpected processed batch size, expected %d, got %d"
,
test
.
name
,
test
.
expectedSuccesses
,
successes
)
}
if
err
!=
test
.
expectedErr
{
t
.
Errorf
(
"%s: unexpected processed batch size, expected %v, got %v"
,
test
.
name
,
test
.
expectedErr
,
err
)
}
// verify that slowStartBatch stops trying more calls after a batch fails
if
callCnt
!=
test
.
expectedCallCnt
{
t
.
Errorf
(
"%s: slowStartBatch() still tries calls after a batch fails, expected %d calls, got %d"
,
test
.
name
,
test
.
expectedCallCnt
,
callCnt
)
}
}
}
func
TestGetPodsToDelete
(
t
*
testing
.
T
)
{
labelMap
:=
map
[
string
]
string
{
"name"
:
"foo"
}
rs
:=
newReplicaSet
(
1
,
labelMap
)
// an unscheduled, pending pod
unscheduledPendingPod
:=
newPod
(
"unscheduled-pending-pod"
,
rs
,
v1
.
PodPending
,
nil
,
true
)
// a scheduled, pending pod
scheduledPendingPod
:=
newPod
(
"scheduled-pending-pod"
,
rs
,
v1
.
PodPending
,
nil
,
true
)
scheduledPendingPod
.
Spec
.
NodeName
=
"fake-node"
// a scheduled, running, not-ready pod
scheduledRunningNotReadyPod
:=
newPod
(
"scheduled-running-not-ready-pod"
,
rs
,
v1
.
PodRunning
,
nil
,
true
)
scheduledRunningNotReadyPod
.
Spec
.
NodeName
=
"fake-node"
scheduledRunningNotReadyPod
.
Status
.
Conditions
=
[]
v1
.
PodCondition
{
{
Type
:
v1
.
PodReady
,
Status
:
v1
.
ConditionFalse
,
},
}
// a scheduled, running, ready pod
scheduledRunningReadyPod
:=
newPod
(
"scheduled-running-ready-pod"
,
rs
,
v1
.
PodRunning
,
nil
,
true
)
scheduledRunningReadyPod
.
Spec
.
NodeName
=
"fake-node"
scheduledRunningReadyPod
.
Status
.
Conditions
=
[]
v1
.
PodCondition
{
{
Type
:
v1
.
PodReady
,
Status
:
v1
.
ConditionTrue
,
},
}
tests
:=
[]
struct
{
name
string
pods
[]
*
v1
.
Pod
diff
int
expectedPodsToDelete
[]
*
v1
.
Pod
}{
// Order used when selecting pods for deletion:
// an unscheduled, pending pod
// a scheduled, pending pod
// a scheduled, running, not-ready pod
// a scheduled, running, ready pod
// Note that a pending pod cannot be ready
{
"len(pods) = 0 (i.e., diff = 0 too)"
,
[]
*
v1
.
Pod
{},
0
,
[]
*
v1
.
Pod
{},
},
{
"diff = len(pods)"
,
[]
*
v1
.
Pod
{
scheduledRunningNotReadyPod
,
scheduledRunningReadyPod
,
},
2
,
[]
*
v1
.
Pod
{
scheduledRunningNotReadyPod
,
scheduledRunningReadyPod
},
},
{
"diff < len(pods)"
,
[]
*
v1
.
Pod
{
scheduledRunningReadyPod
,
scheduledRunningNotReadyPod
,
},
1
,
[]
*
v1
.
Pod
{
scheduledRunningNotReadyPod
},
},
{
"various pod phases and conditions, diff = len(pods)"
,
[]
*
v1
.
Pod
{
scheduledRunningReadyPod
,
scheduledRunningNotReadyPod
,
scheduledPendingPod
,
unscheduledPendingPod
,
},
4
,
[]
*
v1
.
Pod
{
scheduledRunningReadyPod
,
scheduledRunningNotReadyPod
,
scheduledPendingPod
,
unscheduledPendingPod
,
},
},
{
"scheduled vs unscheduled, diff < len(pods)"
,
[]
*
v1
.
Pod
{
scheduledPendingPod
,
unscheduledPendingPod
,
},
1
,
[]
*
v1
.
Pod
{
unscheduledPendingPod
,
},
},
{
"ready vs not-ready, diff < len(pods)"
,
[]
*
v1
.
Pod
{
scheduledRunningReadyPod
,
scheduledRunningNotReadyPod
,
scheduledRunningNotReadyPod
,
},
2
,
[]
*
v1
.
Pod
{
scheduledRunningNotReadyPod
,
scheduledRunningNotReadyPod
,
},
},
{
"pending vs running, diff < len(pods)"
,
[]
*
v1
.
Pod
{
scheduledPendingPod
,
scheduledRunningNotReadyPod
,
},
1
,
[]
*
v1
.
Pod
{
scheduledPendingPod
,
},
},
{
"various pod phases and conditions, diff < len(pods)"
,
[]
*
v1
.
Pod
{
scheduledRunningReadyPod
,
scheduledRunningNotReadyPod
,
scheduledPendingPod
,
unscheduledPendingPod
,
},
3
,
[]
*
v1
.
Pod
{
unscheduledPendingPod
,
scheduledPendingPod
,
scheduledRunningNotReadyPod
,
},
},
}
for
_
,
test
:=
range
tests
{
podsToDelete
:=
getPodsToDelete
(
test
.
pods
,
test
.
diff
)
if
len
(
podsToDelete
)
!=
len
(
test
.
expectedPodsToDelete
)
{
t
.
Errorf
(
"%s: unexpected pods to delete, expected %v, got %v"
,
test
.
name
,
test
.
expectedPodsToDelete
,
podsToDelete
)
}
if
!
reflect
.
DeepEqual
(
podsToDelete
,
test
.
expectedPodsToDelete
)
{
t
.
Errorf
(
"%s: unexpected pods to delete, expected %v, got %v"
,
test
.
name
,
test
.
expectedPodsToDelete
,
podsToDelete
)
}
}
}
func
TestGetPodKeys
(
t
*
testing
.
T
)
{
labelMap
:=
map
[
string
]
string
{
"name"
:
"foo"
}
rs
:=
newReplicaSet
(
1
,
labelMap
)
pod1
:=
newPod
(
"pod1"
,
rs
,
v1
.
PodRunning
,
nil
,
true
)
pod2
:=
newPod
(
"pod2"
,
rs
,
v1
.
PodRunning
,
nil
,
true
)
tests
:=
[]
struct
{
name
string
pods
[]
*
v1
.
Pod
expectedPodKeys
[]
string
}{
{
"len(pods) = 0 (i.e., pods = nil)"
,
[]
*
v1
.
Pod
{},
[]
string
{},
},
{
"len(pods) > 0"
,
[]
*
v1
.
Pod
{
pod1
,
pod2
,
},
[]
string
{
"default/pod1"
,
"default/pod2"
},
},
}
for
_
,
test
:=
range
tests
{
podKeys
:=
getPodKeys
(
test
.
pods
)
if
len
(
podKeys
)
!=
len
(
test
.
expectedPodKeys
)
{
t
.
Errorf
(
"%s: unexpected keys for pods to delete, expected %v, got %v"
,
test
.
name
,
test
.
expectedPodKeys
,
podKeys
)
}
for
i
:=
0
;
i
<
len
(
podKeys
);
i
++
{
if
podKeys
[
i
]
!=
test
.
expectedPodKeys
[
i
]
{
t
.
Errorf
(
"%s: unexpected keys for pods to delete, expected %v, got %v"
,
test
.
name
,
test
.
expectedPodKeys
,
podKeys
)
}
}
}
}
pkg/controller/replicaset/replica_set_utils_test.go
0 → 100644
View file @
d25af7bb
/*
Copyright 2017 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.
*/
// If you make changes to this file, you should also make the corresponding change in ReplicationController.
package
replicaset
import
(
"fmt"
"reflect"
"testing"
"k8s.io/api/core/v1"
extensions
"k8s.io/api/extensions/v1beta1"
)
func
TestCalculateStatus
(
t
*
testing
.
T
)
{
labelMap
:=
map
[
string
]
string
{
"name"
:
"foo"
}
fullLabelMap
:=
map
[
string
]
string
{
"name"
:
"foo"
,
"type"
:
"production"
}
notFullyLabelledRS
:=
newReplicaSet
(
1
,
labelMap
)
// Set replica num to 2 for status condition testing (diff < 0, diff > 0)
fullyLabelledRS
:=
newReplicaSet
(
2
,
fullLabelMap
)
longMinReadySecondsRS
:=
newReplicaSet
(
1
,
fullLabelMap
)
longMinReadySecondsRS
.
Spec
.
MinReadySeconds
=
3600
rsStatusTests
:=
[]
struct
{
name
string
replicaset
*
extensions
.
ReplicaSet
filteredPods
[]
*
v1
.
Pod
expectedReplicaSetStatus
extensions
.
ReplicaSetStatus
}{
{
"1 fully labelled pod"
,
fullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
fullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
1
,
FullyLabeledReplicas
:
1
,
ReadyReplicas
:
1
,
AvailableReplicas
:
1
,
},
},
{
"1 not fully labelled pod"
,
notFullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
notFullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
1
,
FullyLabeledReplicas
:
0
,
ReadyReplicas
:
1
,
AvailableReplicas
:
1
,
},
},
{
"2 fully labelled pods"
,
fullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
fullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
newPod
(
"pod2"
,
fullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
2
,
FullyLabeledReplicas
:
2
,
ReadyReplicas
:
2
,
AvailableReplicas
:
2
,
},
},
{
"2 not fully labelled pods"
,
notFullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
notFullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
newPod
(
"pod2"
,
notFullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
2
,
FullyLabeledReplicas
:
0
,
ReadyReplicas
:
2
,
AvailableReplicas
:
2
,
},
},
{
"1 fully labelled pod, 1 not fully labelled pod"
,
notFullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
notFullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
newPod
(
"pod2"
,
fullyLabelledRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
2
,
FullyLabeledReplicas
:
1
,
ReadyReplicas
:
2
,
AvailableReplicas
:
2
,
},
},
{
"1 non-ready pod"
,
fullyLabelledRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
fullyLabelledRS
,
v1
.
PodPending
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
1
,
FullyLabeledReplicas
:
1
,
ReadyReplicas
:
0
,
AvailableReplicas
:
0
,
},
},
{
"1 ready but non-available pod"
,
longMinReadySecondsRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
longMinReadySecondsRS
,
v1
.
PodRunning
,
nil
,
true
),
},
extensions
.
ReplicaSetStatus
{
Replicas
:
1
,
FullyLabeledReplicas
:
1
,
ReadyReplicas
:
1
,
AvailableReplicas
:
0
,
},
},
}
for
_
,
test
:=
range
rsStatusTests
{
replicaSetStatus
:=
calculateStatus
(
test
.
replicaset
,
test
.
filteredPods
,
nil
)
if
!
reflect
.
DeepEqual
(
replicaSetStatus
,
test
.
expectedReplicaSetStatus
)
{
t
.
Errorf
(
"%s: unexpected replicaset status: expected %v, got %v"
,
test
.
name
,
test
.
expectedReplicaSetStatus
,
replicaSetStatus
)
}
}
}
func
TestCalculateStatusConditions
(
t
*
testing
.
T
)
{
labelMap
:=
map
[
string
]
string
{
"name"
:
"foo"
}
rs
:=
newReplicaSet
(
2
,
labelMap
)
replicaFailureRS
:=
newReplicaSet
(
10
,
labelMap
)
replicaFailureRS
.
Status
.
Conditions
=
[]
extensions
.
ReplicaSetCondition
{
{
Type
:
extensions
.
ReplicaSetReplicaFailure
,
Status
:
v1
.
ConditionTrue
,
},
}
rsStatusConditionTests
:=
[]
struct
{
name
string
replicaset
*
extensions
.
ReplicaSet
filteredPods
[]
*
v1
.
Pod
manageReplicasErr
error
expectedReplicaSetConditions
[]
extensions
.
ReplicaSetCondition
}{
{
"manageReplicasErr != nil && failureCond == nil, diff < 0"
,
rs
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
rs
,
v1
.
PodRunning
,
nil
,
true
),
},
fmt
.
Errorf
(
"fake manageReplicasErr"
),
[]
extensions
.
ReplicaSetCondition
{
{
Type
:
extensions
.
ReplicaSetReplicaFailure
,
Status
:
v1
.
ConditionTrue
,
Reason
:
"FailedCreate"
,
Message
:
"fake manageReplicasErr"
,
},
},
},
{
"manageReplicasErr != nil && failureCond == nil, diff > 0"
,
rs
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
rs
,
v1
.
PodRunning
,
nil
,
true
),
newPod
(
"pod2"
,
rs
,
v1
.
PodRunning
,
nil
,
true
),
newPod
(
"pod3"
,
rs
,
v1
.
PodRunning
,
nil
,
true
),
},
fmt
.
Errorf
(
"fake manageReplicasErr"
),
[]
extensions
.
ReplicaSetCondition
{
{
Type
:
extensions
.
ReplicaSetReplicaFailure
,
Status
:
v1
.
ConditionTrue
,
Reason
:
"FailedDelete"
,
Message
:
"fake manageReplicasErr"
,
},
},
},
{
"manageReplicasErr == nil && failureCond != nil"
,
replicaFailureRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
replicaFailureRS
,
v1
.
PodRunning
,
nil
,
true
),
},
nil
,
nil
,
},
{
"manageReplicasErr != nil && failureCond != nil"
,
replicaFailureRS
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
replicaFailureRS
,
v1
.
PodRunning
,
nil
,
true
),
},
fmt
.
Errorf
(
"fake manageReplicasErr"
),
[]
extensions
.
ReplicaSetCondition
{
{
Type
:
extensions
.
ReplicaSetReplicaFailure
,
Status
:
v1
.
ConditionTrue
,
},
},
},
{
"manageReplicasErr == nil && failureCond == nil"
,
rs
,
[]
*
v1
.
Pod
{
newPod
(
"pod1"
,
rs
,
v1
.
PodRunning
,
nil
,
true
),
},
nil
,
nil
,
},
}
for
_
,
test
:=
range
rsStatusConditionTests
{
replicaSetStatus
:=
calculateStatus
(
test
.
replicaset
,
test
.
filteredPods
,
test
.
manageReplicasErr
)
// all test cases have at most 1 status condition
if
len
(
replicaSetStatus
.
Conditions
)
>
0
{
test
.
expectedReplicaSetConditions
[
0
]
.
LastTransitionTime
=
replicaSetStatus
.
Conditions
[
0
]
.
LastTransitionTime
}
if
!
reflect
.
DeepEqual
(
replicaSetStatus
.
Conditions
,
test
.
expectedReplicaSetConditions
)
{
t
.
Errorf
(
"%s: unexpected replicaset status: expected %v, got %v"
,
test
.
name
,
test
.
expectedReplicaSetConditions
,
replicaSetStatus
.
Conditions
)
}
}
}
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