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
c29d328c
Commit
c29d328c
authored
Apr 23, 2015
by
Victor Marmol
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Kubelet: Add /stats/container endpoint.
This endpoint exposes container stats for all raw containers on the machine. The addition is backwards compatible.
parent
e2f37f81
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
163 additions
and
48 deletions
+163
-48
kubelet.go
pkg/kubelet/kubelet.go
+13
-3
kubelet_test.go
pkg/kubelet/kubelet_test.go
+37
-3
server.go
pkg/kubelet/server.go
+54
-12
server_test.go
pkg/kubelet/server_test.go
+59
-30
No files found.
pkg/kubelet/kubelet.go
View file @
c29d328c
...
@@ -2200,9 +2200,19 @@ func (kl *Kubelet) GetContainerInfo(podFullName string, uid types.UID, container
...
@@ -2200,9 +2200,19 @@ func (kl *Kubelet) GetContainerInfo(podFullName string, uid types.UID, container
return
&
ci
,
nil
return
&
ci
,
nil
}
}
// GetRootInfo returns stats (from Cadvisor) of current machine (root container).
// Returns stats (from Cadvisor) for a non-Kubernetes container.
func
(
kl
*
Kubelet
)
GetRootInfo
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
{
func
(
kl
*
Kubelet
)
GetRawContainerInfo
(
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
,
subcontainers
bool
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
{
return
kl
.
cadvisor
.
ContainerInfo
(
"/"
,
req
)
if
subcontainers
{
return
kl
.
cadvisor
.
SubcontainerInfo
(
containerName
,
req
)
}
else
{
containerInfo
,
err
:=
kl
.
cadvisor
.
ContainerInfo
(
containerName
,
req
)
if
err
!=
nil
{
return
nil
,
err
}
return
map
[
string
]
*
cadvisorApi
.
ContainerInfo
{
containerInfo
.
Name
:
containerInfo
,
},
nil
}
}
}
// GetCachedMachineInfo assumes that the machine info can't change without a reboot
// GetCachedMachineInfo assumes that the machine info can't change without a reboot
...
...
pkg/kubelet/kubelet_test.go
View file @
c29d328c
...
@@ -1441,7 +1441,7 @@ func TestGetContainerInfo(t *testing.T) {
...
@@ -1441,7 +1441,7 @@ func TestGetContainerInfo(t *testing.T) {
mockCadvisor
.
AssertExpectations
(
t
)
mockCadvisor
.
AssertExpectations
(
t
)
}
}
func
TestGetR
ootInfo
(
t
*
testing
.
T
)
{
func
TestGetR
awContainerInfoRoot
(
t
*
testing
.
T
)
{
containerPath
:=
"/"
containerPath
:=
"/"
containerInfo
:=
&
cadvisorApi
.
ContainerInfo
{
containerInfo
:=
&
cadvisorApi
.
ContainerInfo
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
...
@@ -1459,14 +1459,48 @@ func TestGetRootInfo(t *testing.T) {
...
@@ -1459,14 +1459,48 @@ func TestGetRootInfo(t *testing.T) {
cadvisor
:
mockCadvisor
,
cadvisor
:
mockCadvisor
,
}
}
// If the container name is an empty string, then it means the root container.
_
,
err
:=
kubelet
.
GetRawContainerInfo
(
containerPath
,
cadvisorReq
,
false
)
_
,
err
:=
kubelet
.
GetRootInfo
(
cadvisorReq
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
t
.
Errorf
(
"unexpected error: %v"
,
err
)
}
}
mockCadvisor
.
AssertExpectations
(
t
)
mockCadvisor
.
AssertExpectations
(
t
)
}
}
func
TestGetRawContainerInfoSubcontainers
(
t
*
testing
.
T
)
{
containerPath
:=
"/kubelet"
containerInfo
:=
map
[
string
]
*
cadvisorApi
.
ContainerInfo
{
containerPath
:
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
Name
:
containerPath
,
},
},
"/kubelet/sub"
:
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
Name
:
"/kubelet/sub"
,
},
},
}
fakeDocker
:=
dockertools
.
FakeDockerClient
{}
mockCadvisor
:=
&
cadvisor
.
Mock
{}
cadvisorReq
:=
&
cadvisorApi
.
ContainerInfoRequest
{}
mockCadvisor
.
On
(
"SubcontainerInfo"
,
containerPath
,
cadvisorReq
)
.
Return
(
containerInfo
,
nil
)
kubelet
:=
Kubelet
{
dockerClient
:
&
fakeDocker
,
cadvisor
:
mockCadvisor
,
}
result
,
err
:=
kubelet
.
GetRawContainerInfo
(
containerPath
,
cadvisorReq
,
true
)
if
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
}
if
len
(
result
)
!=
2
{
t
.
Errorf
(
"Expected 2 elements, received: %+v"
,
result
)
}
mockCadvisor
.
AssertExpectations
(
t
)
}
func
TestGetContainerInfoWhenCadvisorFailed
(
t
*
testing
.
T
)
{
func
TestGetContainerInfoWhenCadvisorFailed
(
t
*
testing
.
T
)
{
containerID
:=
"ab2cdf"
containerID
:=
"ab2cdf"
...
...
pkg/kubelet/server.go
View file @
c29d328c
...
@@ -99,8 +99,8 @@ func ListenAndServeKubeletReadOnlyServer(host HostInterface, address net.IP, por
...
@@ -99,8 +99,8 @@ func ListenAndServeKubeletReadOnlyServer(host HostInterface, address net.IP, por
// For testablitiy.
// For testablitiy.
type
HostInterface
interface
{
type
HostInterface
interface
{
GetContainerInfo
(
podFullName
string
,
uid
types
.
UID
,
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
GetContainerInfo
(
podFullName
string
,
uid
types
.
UID
,
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
GetRootInfo
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
GetContainerRuntimeVersion
()
(
kubecontainer
.
Version
,
error
)
GetContainerRuntimeVersion
()
(
kubecontainer
.
Version
,
error
)
GetRawContainerInfo
(
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
,
subcontainers
bool
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
GetCachedMachineInfo
()
(
*
cadvisorApi
.
MachineInfo
,
error
)
GetCachedMachineInfo
()
(
*
cadvisorApi
.
MachineInfo
,
error
)
GetPods
()
[]
*
api
.
Pod
GetPods
()
[]
*
api
.
Pod
GetPodByName
(
namespace
,
name
string
)
(
*
api
.
Pod
,
bool
)
GetPodByName
(
namespace
,
name
string
)
(
*
api
.
Pod
,
bool
)
...
@@ -634,26 +634,68 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -634,26 +634,68 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s
.
mux
.
ServeHTTP
(
w
,
req
)
s
.
mux
.
ServeHTTP
(
w
,
req
)
}
}
type
StatsRequest
struct
{
// The name of the container for which to request stats.
// Default: /
ContainerName
string
`json:"containerName,omitempty"`
// Max number of stats to return.
// If start and end time are specified this limit is ignored.
// Default: 60
NumStats
int
`json:"num_stats,omitempty"`
// Start time for which to query information.
// If ommitted, the beginning of time is assumed.
Start
time
.
Time
`json:"start,omitempty"`
// End time for which to query information.
// If ommitted, current time is assumed.
End
time
.
Time
`json:"end,omitempty"`
// Whether to also include information from subcontainers.
// Default: false.
Subcontainers
bool
`json:"subcontainers,omitempty"`
}
// serveStats implements stats logic.
// serveStats implements stats logic.
func
(
s
*
Server
)
serveStats
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
s
*
Server
)
serveStats
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
// /stats/<pod name>/<container name> or /stats/<namespace>/<pod name>/<uid>/<container name>
// Stats requests are in the following forms:
//
// /stats/ : Root container stats
// /stats/container/ : Non-Kubernetes container stats (returns a map)
// /stats/<pod name>/<container name> : Stats for Kubernetes pod/container
// /stats/<namespace>/<pod name>/<uid>/<container name> : Stats for Kubernetes namespace/pod/uid/container
components
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
.
Clean
(
req
.
URL
.
Path
),
"/"
),
"/"
)
components
:=
strings
.
Split
(
strings
.
TrimPrefix
(
path
.
Clean
(
req
.
URL
.
Path
),
"/"
),
"/"
)
var
stats
*
cadvisorApi
.
ContainerInfo
var
stats
interface
{}
var
err
error
var
err
error
query
:=
cadvisorApi
.
DefaultContainerInfoRequest
()
var
query
StatsRequest
query
.
NumStats
=
60
err
=
json
.
NewDecoder
(
req
.
Body
)
.
Decode
(
&
query
)
err
=
json
.
NewDecoder
(
req
.
Body
)
.
Decode
(
&
query
)
if
err
!=
nil
&&
err
!=
io
.
EOF
{
if
err
!=
nil
&&
err
!=
io
.
EOF
{
s
.
error
(
w
,
err
)
s
.
error
(
w
,
err
)
return
return
}
}
cadvisorRequest
:=
cadvisorApi
.
ContainerInfoRequest
{
NumStats
:
query
.
NumStats
,
Start
:
query
.
Start
,
End
:
query
.
End
,
}
switch
len
(
components
)
{
switch
len
(
components
)
{
case
1
:
case
1
:
// Machine stats
// Root container stats.
stats
,
err
=
s
.
host
.
GetRootInfo
(
&
query
)
var
statsMap
map
[
string
]
*
cadvisorApi
.
ContainerInfo
statsMap
,
err
=
s
.
host
.
GetRawContainerInfo
(
"/"
,
&
cadvisorRequest
,
false
)
stats
=
statsMap
[
"/"
]
case
2
:
case
2
:
// pod stats
// Non-Kubernetes container stats.
// TODO(monnand) Implement this
if
components
[
1
]
!=
"container"
{
err
=
errors
.
New
(
"pod level status currently unimplemented"
)
http
.
Error
(
w
,
fmt
.
Sprintf
(
"unknown stats request type %q"
,
components
[
1
]),
http
.
StatusNotFound
)
return
}
containerName
:=
path
.
Join
(
"/"
,
query
.
ContainerName
)
stats
,
err
=
s
.
host
.
GetRawContainerInfo
(
containerName
,
&
cadvisorRequest
,
query
.
Subcontainers
)
case
3
:
case
3
:
// Backward compatibility without uid information, does not support namespace
// Backward compatibility without uid information, does not support namespace
pod
,
ok
:=
s
.
host
.
GetPodByName
(
api
.
NamespaceDefault
,
components
[
1
])
pod
,
ok
:=
s
.
host
.
GetPodByName
(
api
.
NamespaceDefault
,
components
[
1
])
...
@@ -661,16 +703,16 @@ func (s *Server) serveStats(w http.ResponseWriter, req *http.Request) {
...
@@ -661,16 +703,16 @@ func (s *Server) serveStats(w http.ResponseWriter, req *http.Request) {
http
.
Error
(
w
,
"Pod does not exist"
,
http
.
StatusNotFound
)
http
.
Error
(
w
,
"Pod does not exist"
,
http
.
StatusNotFound
)
return
return
}
}
stats
,
err
=
s
.
host
.
GetContainerInfo
(
kubecontainer
.
GetPodFullName
(
pod
),
""
,
components
[
2
],
&
query
)
stats
,
err
=
s
.
host
.
GetContainerInfo
(
kubecontainer
.
GetPodFullName
(
pod
),
""
,
components
[
2
],
&
cadvisorRequest
)
case
5
:
case
5
:
pod
,
ok
:=
s
.
host
.
GetPodByName
(
components
[
1
],
components
[
2
])
pod
,
ok
:=
s
.
host
.
GetPodByName
(
components
[
1
],
components
[
2
])
if
!
ok
{
if
!
ok
{
http
.
Error
(
w
,
"Pod does not exist"
,
http
.
StatusNotFound
)
http
.
Error
(
w
,
"Pod does not exist"
,
http
.
StatusNotFound
)
return
return
}
}
stats
,
err
=
s
.
host
.
GetContainerInfo
(
kubecontainer
.
GetPodFullName
(
pod
),
types
.
UID
(
components
[
3
]),
components
[
4
],
&
query
)
stats
,
err
=
s
.
host
.
GetContainerInfo
(
kubecontainer
.
GetPodFullName
(
pod
),
types
.
UID
(
components
[
3
]),
components
[
4
],
&
cadvisorRequest
)
default
:
default
:
http
.
Error
(
w
,
"unknown resource."
,
http
.
StatusNotFound
)
http
.
Error
(
w
,
fmt
.
Sprintf
(
"Unknown resource: %v"
,
components
)
,
http
.
StatusNotFound
)
return
return
}
}
switch
err
{
switch
err
{
...
...
pkg/kubelet/server_test.go
View file @
c29d328c
...
@@ -17,6 +17,7 @@ limitations under the License.
...
@@ -17,6 +17,7 @@ limitations under the License.
package
kubelet
package
kubelet
import
(
import
(
"bytes"
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"io"
"io"
...
@@ -44,7 +45,7 @@ type fakeKubelet struct {
...
@@ -44,7 +45,7 @@ type fakeKubelet struct {
podByNameFunc
func
(
namespace
,
name
string
)
(
*
api
.
Pod
,
bool
)
podByNameFunc
func
(
namespace
,
name
string
)
(
*
api
.
Pod
,
bool
)
statusFunc
func
(
name
string
)
(
api
.
PodStatus
,
error
)
statusFunc
func
(
name
string
)
(
api
.
PodStatus
,
error
)
containerInfoFunc
func
(
podFullName
string
,
uid
types
.
UID
,
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
containerInfoFunc
func
(
podFullName
string
,
uid
types
.
UID
,
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
r
ootInfoFunc
func
(
query
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
r
awInfoFunc
func
(
query
*
cadvisorApi
.
ContainerInfoRequest
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
machineInfoFunc
func
()
(
*
cadvisorApi
.
MachineInfo
,
error
)
machineInfoFunc
func
()
(
*
cadvisorApi
.
MachineInfo
,
error
)
podsFunc
func
()
[]
*
api
.
Pod
podsFunc
func
()
[]
*
api
.
Pod
logFunc
func
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
logFunc
func
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
...
@@ -69,8 +70,8 @@ func (fk *fakeKubelet) GetContainerInfo(podFullName string, uid types.UID, conta
...
@@ -69,8 +70,8 @@ func (fk *fakeKubelet) GetContainerInfo(podFullName string, uid types.UID, conta
return
fk
.
containerInfoFunc
(
podFullName
,
uid
,
containerName
,
req
)
return
fk
.
containerInfoFunc
(
podFullName
,
uid
,
containerName
,
req
)
}
}
func
(
fk
*
fakeKubelet
)
GetR
ootInfo
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
{
func
(
fk
*
fakeKubelet
)
GetR
awContainerInfo
(
containerName
string
,
req
*
cadvisorApi
.
ContainerInfoRequest
,
subcontainers
bool
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
{
return
fk
.
r
oot
InfoFunc
(
req
)
return
fk
.
r
aw
InfoFunc
(
req
)
}
}
func
(
fk
*
fakeKubelet
)
GetContainerRuntimeVersion
()
(
kubecontainer
.
Version
,
error
)
{
func
(
fk
*
fakeKubelet
)
GetContainerRuntimeVersion
()
(
kubecontainer
.
Version
,
error
)
{
...
@@ -269,9 +270,15 @@ func TestContainerNotFound(t *testing.T) {
...
@@ -269,9 +270,15 @@ func TestContainerNotFound(t *testing.T) {
func
TestRootInfo
(
t
*
testing
.
T
)
{
func
TestRootInfo
(
t
*
testing
.
T
)
{
fw
:=
newServerTest
()
fw
:=
newServerTest
()
expectedInfo
:=
&
cadvisorApi
.
ContainerInfo
{}
expectedInfo
:=
&
cadvisorApi
.
ContainerInfo
{
fw
.
fakeKubelet
.
rootInfoFunc
=
func
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
*
cadvisorApi
.
ContainerInfo
,
error
)
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
return
expectedInfo
,
nil
Name
:
"/"
,
},
}
fw
.
fakeKubelet
.
rawInfoFunc
=
func
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
{
return
map
[
string
]
*
cadvisorApi
.
ContainerInfo
{
expectedInfo
.
Name
:
expectedInfo
,
},
nil
}
}
resp
,
err
:=
http
.
Get
(
fw
.
testHTTPServer
.
URL
+
"/stats"
)
resp
,
err
:=
http
.
Get
(
fw
.
testHTTPServer
.
URL
+
"/stats"
)
...
@@ -285,7 +292,52 @@ func TestRootInfo(t *testing.T) {
...
@@ -285,7 +292,52 @@ func TestRootInfo(t *testing.T) {
t
.
Fatalf
(
"received invalid json data: %v"
,
err
)
t
.
Fatalf
(
"received invalid json data: %v"
,
err
)
}
}
if
!
receivedInfo
.
Eq
(
expectedInfo
)
{
if
!
receivedInfo
.
Eq
(
expectedInfo
)
{
t
.
Errorf
(
"received wrong data: %#v"
,
receivedInfo
)
t
.
Errorf
(
"received wrong data: %#v, expected %#v"
,
receivedInfo
,
expectedInfo
)
}
}
func
TestSubcontainerContainerInfo
(
t
*
testing
.
T
)
{
fw
:=
newServerTest
()
const
kubeletContainer
=
"/kubelet"
const
kubeletSubContainer
=
"/kubelet/sub"
expectedInfo
:=
map
[
string
]
*
cadvisorApi
.
ContainerInfo
{
kubeletContainer
:
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
Name
:
kubeletContainer
,
},
},
kubeletSubContainer
:
{
ContainerReference
:
cadvisorApi
.
ContainerReference
{
Name
:
kubeletSubContainer
,
},
},
}
fw
.
fakeKubelet
.
rawInfoFunc
=
func
(
req
*
cadvisorApi
.
ContainerInfoRequest
)
(
map
[
string
]
*
cadvisorApi
.
ContainerInfo
,
error
)
{
return
expectedInfo
,
nil
}
request
:=
fmt
.
Sprintf
(
"{
\"
containerName
\"
:%q,
\"
subcontainers
\"
: true}"
,
kubeletContainer
)
resp
,
err
:=
http
.
Post
(
fw
.
testHTTPServer
.
URL
+
"/stats/container"
,
"application/json"
,
bytes
.
NewBuffer
([]
byte
(
request
)))
if
err
!=
nil
{
t
.
Fatalf
(
"Got error GETing: %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
var
receivedInfo
map
[
string
]
*
cadvisorApi
.
ContainerInfo
err
=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
receivedInfo
)
if
err
!=
nil
{
t
.
Fatalf
(
"Received invalid json data: %v"
,
err
)
}
if
len
(
receivedInfo
)
!=
len
(
expectedInfo
)
{
t
.
Errorf
(
"Received wrong data: %#v, expected %#v"
,
receivedInfo
,
expectedInfo
)
}
for
_
,
containerName
:=
range
[]
string
{
kubeletContainer
,
kubeletSubContainer
}
{
if
_
,
ok
:=
receivedInfo
[
containerName
];
!
ok
{
t
.
Errorf
(
"Expected container %q to be present in result: %#v"
,
containerName
,
receivedInfo
)
}
if
!
receivedInfo
[
containerName
]
.
Eq
(
expectedInfo
[
containerName
])
{
t
.
Errorf
(
"Invalid result for %q: Expected %#v, received %#v"
,
containerName
,
expectedInfo
[
containerName
],
receivedInfo
[
containerName
])
}
}
}
}
}
...
@@ -426,29 +478,6 @@ func TestServeRunInContainerWithUID(t *testing.T) {
...
@@ -426,29 +478,6 @@ func TestServeRunInContainerWithUID(t *testing.T) {
}
}
}
}
// TODO: fix me when pod level stats get implemented
func
TestPodsInfo
(
t
*
testing
.
T
)
{
fw
:=
newServerTest
()
resp
,
err
:=
http
.
Get
(
fw
.
testHTTPServer
.
URL
+
"/stats/goodpod"
)
if
err
!=
nil
{
t
.
Fatalf
(
"Got error GETing: %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
http
.
StatusInternalServerError
{
t
.
Errorf
(
"expected status code %d, got %d"
,
http
.
StatusInternalServerError
,
resp
.
StatusCode
)
}
body
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
// copying the response body did not work
t
.
Fatalf
(
"Cannot copy resp: %#v"
,
err
)
}
result
:=
string
(
body
)
if
!
strings
.
Contains
(
result
,
"pod level status currently unimplemented"
)
{
t
.
Errorf
(
"expected body contains pod level status currently unimplemented, got %s"
,
result
)
}
}
func
TestHealthCheck
(
t
*
testing
.
T
)
{
func
TestHealthCheck
(
t
*
testing
.
T
)
{
fw
:=
newServerTest
()
fw
:=
newServerTest
()
fw
.
fakeKubelet
.
containerVersionFunc
=
func
()
(
kubecontainer
.
Version
,
error
)
{
fw
.
fakeKubelet
.
containerVersionFunc
=
func
()
(
kubecontainer
.
Version
,
error
)
{
...
...
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