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
c9bd90a5
Commit
c9bd90a5
authored
Jun 05, 2015
by
Mike Danese
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #9032 from andronat/fix_7843
Decrease columns and refactor get pods layout
parents
1d50e973
68d9313d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
124 additions
and
190 deletions
+124
-190
resource_printer.go
pkg/kubectl/resource_printer.go
+46
-89
resource_printer_test.go
pkg/kubectl/resource_printer_test.go
+78
-101
No files found.
pkg/kubectl/resource_printer.go
View file @
c9bd90a5
...
...
@@ -35,7 +35,6 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/volume"
"github.com/docker/docker/pkg/units"
"github.com/ghodss/yaml"
"github.com/golang/glog"
)
...
...
@@ -247,7 +246,7 @@ func (h *HumanReadablePrinter) HandledResources() []string {
return
keys
}
var
podColumns
=
[]
string
{
"
POD"
,
"IP"
,
"CONTAINER(S)"
,
"IMAGE(S)"
,
"HOST"
,
"LABELS"
,
"STATUS"
,
"CREATED"
,
"MESS
AGE"
}
var
podColumns
=
[]
string
{
"
NAME"
,
"READY"
,
"REASON"
,
"RESTARTS"
,
"
AGE"
}
var
podTemplateColumns
=
[]
string
{
"TEMPLATE"
,
"CONTAINER(S)"
,
"IMAGE(S)"
,
"PODLABELS"
}
var
replicationControllerColumns
=
[]
string
{
"CONTROLLER"
,
"CONTAINER(S)"
,
"IMAGE(S)"
,
"SELECTOR"
,
"REPLICAS"
}
var
serviceColumns
=
[]
string
{
"NAME"
,
"LABELS"
,
"SELECTOR"
,
"IP(S)"
,
"PORT(S)"
}
...
...
@@ -350,106 +349,64 @@ func podHostString(host, ip string) string {
return
host
+
"/"
+
ip
}
func
shortHumanDuration
(
d
time
.
Duration
)
string
{
if
seconds
:=
int
(
d
.
Seconds
());
seconds
<
60
{
return
fmt
.
Sprintf
(
"%ds"
,
seconds
)
}
else
if
minutes
:=
int
(
d
.
Minutes
());
minutes
<
60
{
return
fmt
.
Sprintf
(
"%dm"
,
minutes
)
}
else
if
hours
:=
int
(
d
.
Hours
());
hours
<
24
{
return
fmt
.
Sprintf
(
"%dh"
,
hours
)
}
else
if
hours
<
24
*
364
{
return
fmt
.
Sprintf
(
"%dd"
,
hours
/
24
)
}
return
fmt
.
Sprintf
(
"%dy"
,
int
(
d
.
Hours
()
/
24
/
365
))
}
// translateTimestamp returns the elapsed time since timestamp in
// human-readable approximation.
func
translateTimestamp
(
timestamp
util
.
Time
)
string
{
return
units
.
HumanDuration
(
time
.
Now
()
.
Sub
(
timestamp
.
Time
))
}
// interpretContainerStatus interprets the container status and returns strings
// associated with columns "STATUS", "CREATED", and "MESSAGE".
// The meaning of MESSAGE varies based on the context of STATUS:
// STATUS: Waiting; MESSAGE: reason for waiting
// STATUS: Running; MESSAGE: reason for the last termination
// STATUS: Terminated; MESSAGE: reason for this termination
func
interpretContainerStatus
(
status
*
api
.
ContainerStatus
)
(
string
,
string
,
string
,
error
)
{
// Helper function to compose a meaning message from terminate state.
getTermMsg
:=
func
(
state
*
api
.
ContainerStateTerminated
)
string
{
var
message
string
if
state
!=
nil
{
message
=
fmt
.
Sprintf
(
"exit code %d"
,
state
.
ExitCode
)
if
state
.
Reason
!=
""
{
message
=
fmt
.
Sprintf
(
"%s, reason: %s"
,
message
,
state
.
Reason
)
}
}
return
message
}
state
:=
&
status
.
State
if
state
.
Waiting
!=
nil
{
return
"Waiting"
,
""
,
state
.
Waiting
.
Reason
,
nil
}
else
if
state
.
Running
!=
nil
{
// Get the information of the last termination state. This is useful if
// a container is stuck in a crash loop.
message
:=
getTermMsg
(
status
.
LastTerminationState
.
Terminated
)
if
message
!=
""
{
message
=
"last termination: "
+
message
}
stateMsg
:=
"Running"
if
!
status
.
Ready
{
stateMsg
=
stateMsg
+
" *not ready*"
}
return
stateMsg
,
translateTimestamp
(
state
.
Running
.
StartedAt
),
message
,
nil
}
else
if
state
.
Terminated
!=
nil
{
return
"Terminated"
,
translateTimestamp
(
state
.
Terminated
.
StartedAt
),
getTermMsg
(
state
.
Terminated
),
nil
}
return
""
,
""
,
""
,
fmt
.
Errorf
(
"unknown container state %#v"
,
*
state
)
return
shortHumanDuration
(
time
.
Now
()
.
Sub
(
timestamp
.
Time
))
}
func
printPod
(
pod
*
api
.
Pod
,
w
io
.
Writer
,
withNamespace
bool
)
error
{
var
name
string
name
:=
pod
.
Name
if
withNamespace
{
name
=
types
.
NamespacedName
{
pod
.
Namespace
,
pod
.
Name
}
.
String
()
}
else
{
name
=
pod
.
Name
name
=
types
.
NamespacedName
{
Namespace
:
pod
.
Namespace
,
Name
:
pod
.
Name
}
.
String
()
}
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\n
"
,
name
,
pod
.
Status
.
PodIP
,
""
,
""
,
podHostString
(
pod
.
Spec
.
NodeName
,
pod
.
Status
.
HostIP
),
formatLabels
(
pod
.
Labels
),
pod
.
Status
.
Phase
,
translateTimestamp
(
pod
.
CreationTimestamp
),
pod
.
Status
.
Message
,
)
if
err
!=
nil
{
return
err
}
// Lay out all containers on separate lines.
statuses
:=
pod
.
Status
.
ContainerStatuses
if
len
(
statuses
)
==
0
{
// Container status has not been reported yet. Print basic information
// of the containers and exit the function.
for
_
,
container
:=
range
pod
.
Spec
.
Containers
{
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\n
"
,
""
,
""
,
container
.
Name
,
container
.
Image
,
""
,
""
,
""
,
""
,
""
)
if
err
!=
nil
{
return
err
restarts
:=
0
totalContainers
:=
len
(
pod
.
Spec
.
Containers
)
readyContainers
:=
0
reason
:=
string
(
pod
.
Status
.
Phase
)
for
i
:=
len
(
pod
.
Status
.
ContainerStatuses
)
-
1
;
i
>=
0
;
i
--
{
container
:=
pod
.
Status
.
ContainerStatuses
[
i
]
restarts
+=
container
.
RestartCount
if
container
.
State
.
Waiting
!=
nil
&&
container
.
State
.
Waiting
.
Reason
!=
""
{
reason
=
container
.
State
.
Waiting
.
Reason
}
else
if
container
.
State
.
Terminated
!=
nil
&&
container
.
State
.
Terminated
.
Reason
!=
""
{
reason
=
container
.
State
.
Terminated
.
Reason
}
else
if
container
.
State
.
Terminated
!=
nil
&&
container
.
State
.
Terminated
.
Reason
==
""
{
if
container
.
State
.
Terminated
.
Signal
!=
0
{
reason
=
fmt
.
Sprintf
(
"Signal:%d"
,
container
.
State
.
Terminated
.
Signal
)
}
else
{
reason
=
fmt
.
Sprintf
(
"ExitCode:%d"
,
container
.
State
.
Terminated
.
ExitCode
)
}
}
else
if
container
.
Ready
&&
container
.
State
.
Running
!=
nil
{
readyContainers
++
}
return
nil
}
// Print the actual container statuses.
for
_
,
status
:=
range
statuses
{
state
,
created
,
message
,
err
:=
interpretContainerStatus
(
&
status
)
if
err
!=
nil
{
return
err
}
_
,
err
=
fmt
.
Fprintf
(
w
,
"%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\t
%s
\n
"
,
""
,
""
,
status
.
Name
,
status
.
Image
,
""
,
""
,
state
,
created
,
message
,
)
if
err
!=
nil
{
return
err
}
_
,
err
:=
fmt
.
Fprintf
(
w
,
"%s
\t
%d/%d
\t
%s
\t
%d
\t
%s
\n
"
,
name
,
readyContainers
,
totalContainers
,
reason
,
restarts
,
translateTimestamp
(
pod
.
CreationTimestamp
))
if
err
!=
nil
{
return
err
}
return
nil
}
...
...
pkg/kubectl/resource_printer_test.go
View file @
c9bd90a5
...
...
@@ -770,107 +770,6 @@ func TestPrintHumanReadableService(t *testing.T) {
}
}
func
TestInterpretContainerStatus
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
status
*
api
.
ContainerStatus
expectedState
string
expectedMessage
string
expectErr
bool
name
string
}{
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Running
:
&
api
.
ContainerStateRunning
{},
},
Ready
:
true
,
},
expectedState
:
"Running"
,
expectedMessage
:
""
,
name
:
"basic"
,
},
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Running
:
&
api
.
ContainerStateRunning
{},
},
Ready
:
false
,
},
expectedState
:
"Running *not ready*"
,
expectedMessage
:
""
,
name
:
"basic not ready"
,
},
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Waiting
:
&
api
.
ContainerStateWaiting
{},
},
Ready
:
false
,
},
expectedState
:
"Waiting"
,
expectedMessage
:
""
,
name
:
"waiting not ready"
,
},
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Waiting
:
&
api
.
ContainerStateWaiting
{},
},
Ready
:
true
,
},
expectedState
:
"Waiting"
,
expectedMessage
:
""
,
name
:
"waiting"
,
},
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Terminated
:
&
api
.
ContainerStateTerminated
{
ExitCode
:
3
,
},
},
Ready
:
false
,
},
expectedState
:
"Terminated"
,
expectedMessage
:
"exit code 3"
,
name
:
"terminated not ready"
,
},
{
status
:
&
api
.
ContainerStatus
{
State
:
api
.
ContainerState
{
Terminated
:
&
api
.
ContainerStateTerminated
{
ExitCode
:
5
,
Reason
:
"test reason"
,
},
},
Ready
:
true
,
},
expectedState
:
"Terminated"
,
expectedMessage
:
"exit code 5, reason: test reason"
,
name
:
"terminated"
,
},
}
for
_
,
test
:=
range
tests
{
// TODO: test timestamp printing.
state
,
_
,
msg
,
err
:=
interpretContainerStatus
(
test
.
status
)
if
test
.
expectErr
&&
err
==
nil
{
t
.
Errorf
(
"unexpected non-error (%s)"
,
test
.
name
)
continue
}
if
!
test
.
expectErr
&&
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v (%s)"
,
err
,
test
.
name
)
continue
}
if
state
!=
test
.
expectedState
{
t
.
Errorf
(
"expected: %s, got: %s"
,
test
.
expectedState
,
state
)
}
if
msg
!=
test
.
expectedMessage
{
t
.
Errorf
(
"expected: %s, got: %s"
,
test
.
expectedMessage
,
msg
)
}
}
}
func
TestPrintHumanReadableWithNamespace
(
t
*
testing
.
T
)
{
namespaceName
:=
"testnamespace"
name
:=
"test"
...
...
@@ -1050,3 +949,81 @@ func TestPrintHumanReadableWithNamespace(t *testing.T) {
}
}
}
func
TestPrintPod
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
pod
api
.
Pod
expect
string
}{
{
// Test name, num of containers, restarts, container ready status
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test1"
},
Spec
:
api
.
PodSpec
{
Containers
:
make
([]
api
.
Container
,
2
)},
Status
:
api
.
PodStatus
{
Phase
:
"podPhase"
,
ContainerStatuses
:
[]
api
.
ContainerStatus
{
{
Ready
:
true
,
RestartCount
:
3
,
State
:
api
.
ContainerState
{
Running
:
&
api
.
ContainerStateRunning
{}}},
{
RestartCount
:
3
},
},
},
},
"test1
\t
1/2
\t
podPhase
\t
6
\t
"
,
},
{
// Test container error overwrites pod phase
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test2"
},
Spec
:
api
.
PodSpec
{
Containers
:
make
([]
api
.
Container
,
2
)},
Status
:
api
.
PodStatus
{
Phase
:
"podPhase"
,
ContainerStatuses
:
[]
api
.
ContainerStatus
{
{
Ready
:
true
,
RestartCount
:
3
,
State
:
api
.
ContainerState
{
Running
:
&
api
.
ContainerStateRunning
{}}},
{
State
:
api
.
ContainerState
{
Waiting
:
&
api
.
ContainerStateWaiting
{
Reason
:
"containerWaitingReason"
}},
RestartCount
:
3
},
},
},
},
"test2
\t
1/2
\t
containerWaitingReason
\t
6
\t
"
,
},
{
// Test the same as the above but with Terminated state and the first container overwrites the rest
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test3"
},
Spec
:
api
.
PodSpec
{
Containers
:
make
([]
api
.
Container
,
2
)},
Status
:
api
.
PodStatus
{
Phase
:
"podPhase"
,
ContainerStatuses
:
[]
api
.
ContainerStatus
{
{
State
:
api
.
ContainerState
{
Waiting
:
&
api
.
ContainerStateWaiting
{
Reason
:
"containerWaitingReason"
}},
RestartCount
:
3
},
{
State
:
api
.
ContainerState
{
Terminated
:
&
api
.
ContainerStateTerminated
{
Reason
:
"containerTerminatedReason"
}},
RestartCount
:
3
},
},
},
},
"test3
\t
0/2
\t
containerWaitingReason
\t
6
\t
"
,
},
{
// Test ready is not enough for reporting running
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test4"
},
Spec
:
api
.
PodSpec
{
Containers
:
make
([]
api
.
Container
,
2
)},
Status
:
api
.
PodStatus
{
Phase
:
"podPhase"
,
ContainerStatuses
:
[]
api
.
ContainerStatus
{
{
Ready
:
true
,
RestartCount
:
3
,
State
:
api
.
ContainerState
{
Running
:
&
api
.
ContainerStateRunning
{}}},
{
Ready
:
true
,
RestartCount
:
3
},
},
},
},
"test4
\t
1/2
\t
podPhase
\t
6
\t
"
,
},
}
buf
:=
bytes
.
NewBuffer
([]
byte
{})
for
_
,
test
:=
range
tests
{
printPod
(
&
test
.
pod
,
buf
,
false
)
// We ignore time
if
!
strings
.
HasPrefix
(
buf
.
String
(),
test
.
expect
)
{
t
.
Fatalf
(
"Expected: %s, got: %s"
,
test
.
expect
,
buf
.
String
())
}
buf
.
Reset
()
}
}
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