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
5f8f607c
Commit
5f8f607c
authored
Oct 09, 2018
by
Sean Sullivan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kubectl: copy pod utils into util/podutils package
parent
539bdbc3
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
232 additions
and
14 deletions
+232
-14
BUILD
pkg/kubectl/BUILD
+1
-1
BUILD
pkg/kubectl/polymorphichelpers/BUILD
+2
-2
attachablepodforobject.go
pkg/kubectl/polymorphichelpers/attachablepodforobject.go
+2
-2
helpers_test.go
pkg/kubectl/polymorphichelpers/helpers_test.go
+5
-5
logsforobject.go
pkg/kubectl/polymorphichelpers/logsforobject.go
+2
-2
rolling_updater.go
pkg/kubectl/rolling_updater.go
+2
-2
BUILD
pkg/kubectl/util/BUILD
+1
-0
BUILD
pkg/kubectl/util/podutils/BUILD
+27
-0
podutils.go
pkg/kubectl/util/podutils/podutils.go
+190
-0
No files found.
pkg/kubectl/BUILD
View file @
5f8f607c
...
...
@@ -109,7 +109,6 @@ go_library(
],
importpath = "k8s.io/kubernetes/pkg/kubectl",
deps = [
"//pkg/api/v1/pod:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/core/v1:go_default_library",
"//pkg/controller/deployment/util:go_default_library",
...
...
@@ -118,6 +117,7 @@ go_library(
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util:go_default_library",
"//pkg/kubectl/util/hash:go_default_library",
"//pkg/kubectl/util/podutils:go_default_library",
"//pkg/kubectl/util/slice:go_default_library",
"//pkg/printers:go_default_library",
"//pkg/printers/internalversion:go_default_library",
...
...
pkg/kubectl/polymorphichelpers/BUILD
View file @
5f8f607c
...
...
@@ -22,9 +22,9 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers",
visibility = ["//visibility:public"],
deps = [
"//pkg/controller:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/podutils:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/apps/v1beta1:go_default_library",
"//staging/src/k8s.io/api/apps/v1beta2:go_default_library",
...
...
@@ -63,7 +63,7 @@ go_test(
],
embed = [":go_default_library"],
deps = [
"//pkg/
controller
:go_default_library",
"//pkg/
kubectl/util/podutils
:go_default_library",
"//staging/src/k8s.io/api/apps/v1:go_default_library",
"//staging/src/k8s.io/api/apps/v1beta1:go_default_library",
"//staging/src/k8s.io/api/apps/v1beta2:go_default_library",
...
...
pkg/kubectl/polymorphichelpers/attachablepodforobject.go
View file @
5f8f607c
...
...
@@ -25,7 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
corev1client
"k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/kubernetes/pkg/
controller
"
"k8s.io/kubernetes/pkg/
kubectl/util/podutils
"
)
// attachablePodForObject returns the pod to which to attach given an object.
...
...
@@ -48,7 +48,7 @@ func attachablePodForObject(restClientGetter genericclioptions.RESTClientGetter,
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"cannot attach to %T: %v"
,
object
,
err
)
}
sortBy
:=
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
controller
.
ActivePods
(
pods
))
}
sortBy
:=
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
podutils
.
ActivePods
(
pods
))
}
pod
,
_
,
err
:=
GetFirstPod
(
clientset
,
namespace
,
selector
.
String
(),
timeout
,
sortBy
)
return
pod
,
err
}
pkg/kubectl/polymorphichelpers/helpers_test.go
View file @
5f8f607c
...
...
@@ -29,7 +29,7 @@ import (
"k8s.io/apimachinery/pkg/watch"
fakeexternal
"k8s.io/client-go/kubernetes/fake"
testcore
"k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/
controller
"
"k8s.io/kubernetes/pkg/
kubectl/util/podutils
"
)
func
TestGetFirstPod
(
t
*
testing
.
T
)
{
...
...
@@ -48,7 +48,7 @@ func TestGetFirstPod(t *testing.T) {
{
name
:
"kubectl logs - two ready pods"
,
podList
:
newPodList
(
2
,
-
1
,
-
1
,
labelSet
),
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
controller
.
ByLogging
(
pods
)
},
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
podutils
.
ByLogging
(
pods
)
},
expected
:
&
corev1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"pod-1"
,
...
...
@@ -70,7 +70,7 @@ func TestGetFirstPod(t *testing.T) {
{
name
:
"kubectl logs - one unhealthy, one healthy"
,
podList
:
newPodList
(
2
,
-
1
,
1
,
labelSet
),
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
controller
.
ByLogging
(
pods
)
},
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
podutils
.
ByLogging
(
pods
)
},
expected
:
&
corev1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"pod-2"
,
...
...
@@ -93,7 +93,7 @@ func TestGetFirstPod(t *testing.T) {
{
name
:
"kubectl attach - two ready pods"
,
podList
:
newPodList
(
2
,
-
1
,
-
1
,
labelSet
),
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
controller
.
ActivePods
(
pods
))
},
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
podutils
.
ActivePods
(
pods
))
},
expected
:
&
corev1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"pod-1"
,
...
...
@@ -136,7 +136,7 @@ func TestGetFirstPod(t *testing.T) {
},
},
},
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
controller
.
ActivePods
(
pods
))
},
sortBy
:
func
(
pods
[]
*
corev1
.
Pod
)
sort
.
Interface
{
return
sort
.
Reverse
(
podutils
.
ActivePods
(
pods
))
},
expected
:
&
corev1
.
Pod
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"pod-1"
,
...
...
pkg/kubectl/polymorphichelpers/logsforobject.go
View file @
5f8f607c
...
...
@@ -29,7 +29,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
corev1client
"k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/rest"
"k8s.io/kubernetes/pkg/
controller
"
"k8s.io/kubernetes/pkg/
kubectl/util/podutils
"
)
func
logsForObject
(
restClientGetter
genericclioptions
.
RESTClientGetter
,
object
,
options
runtime
.
Object
,
timeout
time
.
Duration
,
allContainers
bool
)
([]
*
rest
.
Request
,
error
)
{
...
...
@@ -99,7 +99,7 @@ func logsForObjectWithClient(clientset corev1client.CoreV1Interface, object, opt
return
nil
,
fmt
.
Errorf
(
"cannot get the logs from %T: %v"
,
object
,
err
)
}
sortBy
:=
func
(
pods
[]
*
v1
.
Pod
)
sort
.
Interface
{
return
controller
.
ByLogging
(
pods
)
}
sortBy
:=
func
(
pods
[]
*
v1
.
Pod
)
sort
.
Interface
{
return
podutils
.
ByLogging
(
pods
)
}
pod
,
numPods
,
err
:=
GetFirstPod
(
clientset
,
namespace
,
selector
.
String
(),
timeout
,
sortBy
)
if
err
!=
nil
{
return
nil
,
err
...
...
pkg/kubectl/rolling_updater.go
View file @
5f8f607c
...
...
@@ -35,9 +35,9 @@ import (
scaleclient
"k8s.io/client-go/scale"
"k8s.io/client-go/util/integer"
"k8s.io/client-go/util/retry"
podutil
"k8s.io/kubernetes/pkg/api/v1/pod"
deploymentutil
"k8s.io/kubernetes/pkg/controller/deployment/util"
"k8s.io/kubernetes/pkg/kubectl/util"
"k8s.io/kubernetes/pkg/kubectl/util/podutils"
)
func
newInt32Ptr
(
val
int
)
*
int32
{
...
...
@@ -443,7 +443,7 @@ func (r *RollingUpdater) readyPods(oldRc, newRc *corev1.ReplicationController, m
if
v1Pod
.
DeletionTimestamp
!=
nil
{
continue
}
if
!
podutil
.
IsPodAvailable
(
&
v1Pod
,
minReadySeconds
,
r
.
nowFn
())
{
if
!
podutil
s
.
IsPodAvailable
(
&
v1Pod
,
minReadySeconds
,
r
.
nowFn
())
{
continue
}
switch
controller
.
Name
{
...
...
pkg/kubectl/util/BUILD
View file @
5f8f607c
...
...
@@ -69,6 +69,7 @@ filegroup(
"//pkg/kubectl/util/hash:all-srcs",
"//pkg/kubectl/util/i18n:all-srcs",
"//pkg/kubectl/util/logs:all-srcs",
"//pkg/kubectl/util/podutils:all-srcs",
"//pkg/kubectl/util/slice:all-srcs",
"//pkg/kubectl/util/term:all-srcs",
],
...
...
pkg/kubectl/util/podutils/BUILD
0 → 100644
View file @
5f8f607c
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["podutils.go"],
importpath = "k8s.io/kubernetes/pkg/kubectl/util/podutils",
visibility = ["//visibility:public"],
deps = [
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/client-go/util/integer:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
pkg/kubectl/util/podutils/podutils.go
0 → 100644
View file @
5f8f607c
/*
Copyright 2014 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
podutils
import
(
"time"
corev1
"k8s.io/api/core/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/util/integer"
)
// IsPodAvailable returns true if a pod is available; false otherwise.
// Precondition for an available pod is that it must be ready. On top
// of that, there are two cases when a pod can be considered available:
// 1. minReadySeconds == 0, or
// 2. LastTransitionTime (is set) + minReadySeconds < current time
func
IsPodAvailable
(
pod
*
corev1
.
Pod
,
minReadySeconds
int32
,
now
metav1
.
Time
)
bool
{
if
!
IsPodReady
(
pod
)
{
return
false
}
c
:=
getPodReadyCondition
(
pod
.
Status
)
minReadySecondsDuration
:=
time
.
Duration
(
minReadySeconds
)
*
time
.
Second
if
minReadySeconds
==
0
||
!
c
.
LastTransitionTime
.
IsZero
()
&&
c
.
LastTransitionTime
.
Add
(
minReadySecondsDuration
)
.
Before
(
now
.
Time
)
{
return
true
}
return
false
}
// IsPodReady returns true if a pod is ready; false otherwise.
func
IsPodReady
(
pod
*
corev1
.
Pod
)
bool
{
return
isPodReadyConditionTrue
(
pod
.
Status
)
}
// IsPodReadyConditionTrue returns true if a pod is ready; false otherwise.
func
isPodReadyConditionTrue
(
status
corev1
.
PodStatus
)
bool
{
condition
:=
getPodReadyCondition
(
status
)
return
condition
!=
nil
&&
condition
.
Status
==
corev1
.
ConditionTrue
}
// GetPodReadyCondition extracts the pod ready condition from the given status and returns that.
// Returns nil if the condition is not present.
func
getPodReadyCondition
(
status
corev1
.
PodStatus
)
*
corev1
.
PodCondition
{
_
,
condition
:=
getPodCondition
(
&
status
,
corev1
.
PodReady
)
return
condition
}
// GetPodCondition extracts the provided condition from the given status and returns that.
// Returns nil and -1 if the condition is not present, and the index of the located condition.
func
getPodCondition
(
status
*
corev1
.
PodStatus
,
conditionType
corev1
.
PodConditionType
)
(
int
,
*
corev1
.
PodCondition
)
{
if
status
==
nil
{
return
-
1
,
nil
}
return
getPodConditionFromList
(
status
.
Conditions
,
conditionType
)
}
// GetPodConditionFromList extracts the provided condition from the given list of condition and
// returns the index of the condition and the condition. Returns -1 and nil if the condition is not present.
func
getPodConditionFromList
(
conditions
[]
corev1
.
PodCondition
,
conditionType
corev1
.
PodConditionType
)
(
int
,
*
corev1
.
PodCondition
)
{
if
conditions
==
nil
{
return
-
1
,
nil
}
for
i
:=
range
conditions
{
if
conditions
[
i
]
.
Type
==
conditionType
{
return
i
,
&
conditions
[
i
]
}
}
return
-
1
,
nil
}
// ByLogging allows custom sorting of pods so the best one can be picked for getting its logs.
type
ByLogging
[]
*
corev1
.
Pod
func
(
s
ByLogging
)
Len
()
int
{
return
len
(
s
)
}
func
(
s
ByLogging
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
func
(
s
ByLogging
)
Less
(
i
,
j
int
)
bool
{
// 1. assigned < unassigned
if
s
[
i
]
.
Spec
.
NodeName
!=
s
[
j
]
.
Spec
.
NodeName
&&
(
len
(
s
[
i
]
.
Spec
.
NodeName
)
==
0
||
len
(
s
[
j
]
.
Spec
.
NodeName
)
==
0
)
{
return
len
(
s
[
i
]
.
Spec
.
NodeName
)
>
0
}
// 2. PodRunning < PodUnknown < PodPending
m
:=
map
[
corev1
.
PodPhase
]
int
{
corev1
.
PodRunning
:
0
,
corev1
.
PodUnknown
:
1
,
corev1
.
PodPending
:
2
}
if
m
[
s
[
i
]
.
Status
.
Phase
]
!=
m
[
s
[
j
]
.
Status
.
Phase
]
{
return
m
[
s
[
i
]
.
Status
.
Phase
]
<
m
[
s
[
j
]
.
Status
.
Phase
]
}
// 3. ready < not ready
if
IsPodReady
(
s
[
i
])
!=
IsPodReady
(
s
[
j
])
{
return
IsPodReady
(
s
[
i
])
}
// TODO: take availability into account when we push minReadySeconds information from deployment into pods,
// see https://github.com/kubernetes/kubernetes/issues/22065
// 4. Been ready for more time < less time < empty time
if
IsPodReady
(
s
[
i
])
&&
IsPodReady
(
s
[
j
])
&&
!
podReadyTime
(
s
[
i
])
.
Equal
(
podReadyTime
(
s
[
j
]))
{
return
afterOrZero
(
podReadyTime
(
s
[
j
]),
podReadyTime
(
s
[
i
]))
}
// 5. Pods with containers with higher restart counts < lower restart counts
if
maxContainerRestarts
(
s
[
i
])
!=
maxContainerRestarts
(
s
[
j
])
{
return
maxContainerRestarts
(
s
[
i
])
>
maxContainerRestarts
(
s
[
j
])
}
// 6. older pods < newer pods < empty timestamp pods
if
!
s
[
i
]
.
CreationTimestamp
.
Equal
(
&
s
[
j
]
.
CreationTimestamp
)
{
return
afterOrZero
(
&
s
[
j
]
.
CreationTimestamp
,
&
s
[
i
]
.
CreationTimestamp
)
}
return
false
}
// ActivePods type allows custom sorting of pods so a controller can pick the best ones to delete.
type
ActivePods
[]
*
corev1
.
Pod
func
(
s
ActivePods
)
Len
()
int
{
return
len
(
s
)
}
func
(
s
ActivePods
)
Swap
(
i
,
j
int
)
{
s
[
i
],
s
[
j
]
=
s
[
j
],
s
[
i
]
}
func
(
s
ActivePods
)
Less
(
i
,
j
int
)
bool
{
// 1. Unassigned < assigned
// If only one of the pods is unassigned, the unassigned one is smaller
if
s
[
i
]
.
Spec
.
NodeName
!=
s
[
j
]
.
Spec
.
NodeName
&&
(
len
(
s
[
i
]
.
Spec
.
NodeName
)
==
0
||
len
(
s
[
j
]
.
Spec
.
NodeName
)
==
0
)
{
return
len
(
s
[
i
]
.
Spec
.
NodeName
)
==
0
}
// 2. PodPending < PodUnknown < PodRunning
m
:=
map
[
corev1
.
PodPhase
]
int
{
corev1
.
PodPending
:
0
,
corev1
.
PodUnknown
:
1
,
corev1
.
PodRunning
:
2
}
if
m
[
s
[
i
]
.
Status
.
Phase
]
!=
m
[
s
[
j
]
.
Status
.
Phase
]
{
return
m
[
s
[
i
]
.
Status
.
Phase
]
<
m
[
s
[
j
]
.
Status
.
Phase
]
}
// 3. Not ready < ready
// If only one of the pods is not ready, the not ready one is smaller
if
IsPodReady
(
s
[
i
])
!=
IsPodReady
(
s
[
j
])
{
return
!
IsPodReady
(
s
[
i
])
}
// TODO: take availability into account when we push minReadySeconds information from deployment into pods,
// see https://github.com/kubernetes/kubernetes/issues/22065
// 4. Been ready for empty time < less time < more time
// If both pods are ready, the latest ready one is smaller
if
IsPodReady
(
s
[
i
])
&&
IsPodReady
(
s
[
j
])
&&
!
podReadyTime
(
s
[
i
])
.
Equal
(
podReadyTime
(
s
[
j
]))
{
return
afterOrZero
(
podReadyTime
(
s
[
i
]),
podReadyTime
(
s
[
j
]))
}
// 5. Pods with containers with higher restart counts < lower restart counts
if
maxContainerRestarts
(
s
[
i
])
!=
maxContainerRestarts
(
s
[
j
])
{
return
maxContainerRestarts
(
s
[
i
])
>
maxContainerRestarts
(
s
[
j
])
}
// 6. Empty creation time pods < newer pods < older pods
if
!
s
[
i
]
.
CreationTimestamp
.
Equal
(
&
s
[
j
]
.
CreationTimestamp
)
{
return
afterOrZero
(
&
s
[
i
]
.
CreationTimestamp
,
&
s
[
j
]
.
CreationTimestamp
)
}
return
false
}
// afterOrZero checks if time t1 is after time t2; if one of them
// is zero, the zero time is seen as after non-zero time.
func
afterOrZero
(
t1
,
t2
*
metav1
.
Time
)
bool
{
if
t1
.
Time
.
IsZero
()
||
t2
.
Time
.
IsZero
()
{
return
t1
.
Time
.
IsZero
()
}
return
t1
.
After
(
t2
.
Time
)
}
func
podReadyTime
(
pod
*
corev1
.
Pod
)
*
metav1
.
Time
{
if
IsPodReady
(
pod
)
{
for
_
,
c
:=
range
pod
.
Status
.
Conditions
{
// we only care about pod ready conditions
if
c
.
Type
==
corev1
.
PodReady
&&
c
.
Status
==
corev1
.
ConditionTrue
{
return
&
c
.
LastTransitionTime
}
}
}
return
&
metav1
.
Time
{}
}
func
maxContainerRestarts
(
pod
*
corev1
.
Pod
)
int
{
maxRestarts
:=
0
for
_
,
c
:=
range
pod
.
Status
.
ContainerStatuses
{
maxRestarts
=
integer
.
IntMax
(
maxRestarts
,
int
(
c
.
RestartCount
))
}
return
maxRestarts
}
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