Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
凌波微步_大先生
dashboard
提交
5b450ece
D
dashboard
项目概览
凌波微步_大先生
/
dashboard
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dashboard
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
5b450ece
编写于
5月 16, 2016
作者:
S
Sebastian Florek
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add related pods to service detail page. Refactor heapster client to allow testing. (#739)
上级
597f6e47
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
152 addition
and
15 deletion
+152
-15
src/app/backend/client/heapsterclient.go
src/app/backend/client/heapsterclient.go
+8
-3
src/app/backend/handler/apihandler.go
src/app/backend/handler/apihandler.go
+2
-1
src/app/backend/resource/service/servicedetail.go
src/app/backend/resource/service/servicedetail.go
+35
-2
src/app/externs/backendapi.js
src/app/externs/backendapi.js
+2
-1
src/app/frontend/servicedetail/servicedetail.html
src/app/frontend/servicedetail/servicedetail.html
+7
-0
src/test/backend/resource/replicaset/replicasetdetail_test.go
...test/backend/resource/replicaset/replicasetdetail_test.go
+4
-3
src/test/backend/resource/service/servicedetail_test.go
src/test/backend/resource/service/servicedetail_test.go
+94
-5
未找到文件。
src/app/backend/client/heapsterclient.go
浏览文件 @
5b450ece
...
...
@@ -26,8 +26,13 @@ type HeapsterClient interface {
// Creates a new GET HTTP request to heapster, specified by the path param, to the V1 API
// endpoint. The path param is without the API prefix, e.g.,
// /model/namespaces/default/pod-list/foo/metrics/memory-usage
Get
(
path
string
)
RequestInterface
}
Get
(
path
string
)
*
restclient
.
Request
// RequestInterface is an interface that allows to make operations on pure request object.
// Separation is done to allow testing.
type
RequestInterface
interface
{
DoRaw
()
([]
byte
,
error
)
}
// InClusterHeapsterClient is an in-cluster implementation of a Heapster client. Talks with Heapster
...
...
@@ -37,7 +42,7 @@ type InClusterHeapsterClient struct {
}
// InClusterHeapsterClient.Get creates request to given path.
func
(
c
InClusterHeapsterClient
)
Get
(
path
string
)
*
restclient
.
Request
{
func
(
c
InClusterHeapsterClient
)
Get
(
path
string
)
RequestInterface
{
return
c
.
client
.
Get
()
.
Prefix
(
"proxy"
)
.
Namespace
(
"kube-system"
)
.
Resource
(
"services"
)
.
...
...
@@ -52,7 +57,7 @@ type RemoteHeapsterClient struct {
}
// RemoteHeapsterClient.Get creates request to given path.
func
(
c
RemoteHeapsterClient
)
Get
(
path
string
)
*
restclient
.
Request
{
func
(
c
RemoteHeapsterClient
)
Get
(
path
string
)
RequestInterface
{
return
c
.
client
.
Get
()
.
Suffix
(
path
)
}
...
...
src/app/backend/handler/apihandler.go
浏览文件 @
5b450ece
...
...
@@ -300,7 +300,8 @@ func (apiHandler *ApiHandler) handleGetServiceList(request *restful.Request, res
func
(
apiHandler
*
ApiHandler
)
handleGetServiceDetail
(
request
*
restful
.
Request
,
response
*
restful
.
Response
)
{
namespace
:=
request
.
PathParameter
(
"namespace"
)
service
:=
request
.
PathParameter
(
"service"
)
result
,
err
:=
resourceService
.
GetServiceDetail
(
apiHandler
.
client
,
namespace
,
service
)
result
,
err
:=
resourceService
.
GetServiceDetail
(
apiHandler
.
client
,
apiHandler
.
heapsterClient
,
namespace
,
service
)
if
err
!=
nil
{
handleInternalError
(
response
,
err
)
return
...
...
src/app/backend/resource/service/servicedetail.go
浏览文件 @
5b450ece
...
...
@@ -18,9 +18,11 @@ import (
"log"
"k8s.io/kubernetes/pkg/api"
c
lient
"k8s.io/kubernetes/pkg/client/unversioned"
k8sC
lient
"k8s.io/kubernetes/pkg/client/unversioned"
"github.com/kubernetes/dashboard/client"
"github.com/kubernetes/dashboard/resource/common"
"github.com/kubernetes/dashboard/resource/pod"
)
// Service is a representation of a service.
...
...
@@ -45,10 +47,15 @@ type ServiceDetail struct {
// ClusterIP is usually assigned by the master. Valid values are None, empty string (""), or
// a valid IP address. None can be specified for headless services when proxying is not required
ClusterIP
string
`json:"clusterIP"`
// PodList represents list of pods targeted by same label selector as this service.
PodList
pod
.
PodList
`json:"podList"`
}
// GetServiceDetail gets service details.
func
GetServiceDetail
(
client
client
.
Interface
,
namespace
,
name
string
)
(
*
ServiceDetail
,
error
)
{
func
GetServiceDetail
(
client
k8sClient
.
Interface
,
heapsterClient
client
.
HeapsterClient
,
namespace
,
name
string
)
(
*
ServiceDetail
,
error
)
{
log
.
Printf
(
"Getting details of %s service in %s namespace"
,
name
,
namespace
)
// TODO(maciaszczykm): Use channels.
...
...
@@ -57,6 +64,32 @@ func GetServiceDetail(client client.Interface, namespace, name string) (*Service
return
nil
,
err
}
podList
,
err
:=
GetServicePods
(
client
,
heapsterClient
,
namespace
,
serviceData
.
Spec
.
Selector
)
if
err
!=
nil
{
return
nil
,
err
}
service
:=
ToServiceDetail
(
serviceData
)
service
.
PodList
=
*
podList
return
&
service
,
nil
}
// GetServicePods gets list of pods targeted by given label selector in given namespace.
func
GetServicePods
(
client
k8sClient
.
Interface
,
heapsterClient
client
.
HeapsterClient
,
namespace
string
,
serviceSelector
map
[
string
]
string
)
(
*
pod
.
PodList
,
error
)
{
channels
:=
&
common
.
ResourceChannels
{
PodList
:
common
.
GetPodListChannel
(
client
,
1
),
}
apiPodList
:=
<-
channels
.
PodList
.
List
if
err
:=
<-
channels
.
PodList
.
Error
;
err
!=
nil
{
return
nil
,
err
}
apiPods
:=
common
.
FilterNamespacedPodsBySelector
(
apiPodList
.
Items
,
namespace
,
serviceSelector
)
podList
:=
pod
.
CreatePodList
(
apiPods
,
heapsterClient
)
return
&
podList
,
nil
}
src/app/externs/backendapi.js
浏览文件 @
5b450ece
...
...
@@ -284,7 +284,8 @@ backendApi.Pod;
* externalEndpoints: !Array<!backendApi.Endpoint>,
* selector: !Object<string, string>,
* type: string,
* clusterIP: string
* clusterIP: string,
* podList: !backendApi.PodList
* }}
*/
backendApi
.
ServiceDetail
;
...
...
src/app/frontend/servicedetail/servicedetail.html
浏览文件 @
5b450ece
...
...
@@ -15,3 +15,10 @@ limitations under the License.
-->
<kd-service-info
service=
"ctrl.serviceDetail"
></kd-service-info>
<kd-content-card
ng-if=
"ctrl.serviceDetail.podList.pods.length"
>
<kd-title>
Pods
</kd-title>
<kd-content>
<kd-pod-card-list
pod-list=
"ctrl.serviceDetail.podList"
></kd-pod-card-list>
</kd-content>
</kd-content-card>
src/test/backend/resource/replicaset/replicasetdetail_test.go
浏览文件 @
5b450ece
...
...
@@ -19,21 +19,22 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/restclient"
k8sClient
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
"github.com/kubernetes/dashboard/client"
"github.com/kubernetes/dashboard/resource/common"
"github.com/kubernetes/dashboard/resource/pod"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
)
type
FakeHeapsterClient
struct
{
client
k8sClient
.
Interface
}
func
(
c
FakeHeapsterClient
)
Get
(
path
string
)
*
restclient
.
Request
{
func
(
c
FakeHeapsterClient
)
Get
(
path
string
)
client
.
RequestInterface
{
return
&
restclient
.
Request
{}
}
...
...
src/test/backend/resource/service/servicedetail_test.go
浏览文件 @
5b450ece
...
...
@@ -19,11 +19,28 @@ import (
"testing"
"k8s.io/kubernetes/pkg/api"
k8sClient
"k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/unversioned/testclient"
"github.com/kubernetes/dashboard/client"
"github.com/kubernetes/dashboard/resource/common"
"github.com/kubernetes/dashboard/resource/pod"
)
type
FakeHeapsterClient
struct
{
client
k8sClient
.
Interface
}
type
FakeRequest
struct
{}
func
(
FakeRequest
)
DoRaw
()
([]
byte
,
error
)
{
return
nil
,
nil
}
func
(
c
FakeHeapsterClient
)
Get
(
path
string
)
client
.
RequestInterface
{
return
FakeRequest
{}
}
func
TestGetServiceDetail
(
t
*
testing
.
T
)
{
cases
:=
[]
struct
{
service
*
api
.
Service
...
...
@@ -33,17 +50,18 @@ func TestGetServiceDetail(t *testing.T) {
}{
{
service
:
&
api
.
Service
{},
namespace
:
"test-namespace"
,
name
:
"test-name"
,
expectedActions
:
[]
string
{
"get"
},
namespace
:
"test-namespace
-1
"
,
name
:
"test-name"
,
expectedActions
:
[]
string
{
"get"
,
"list"
},
expected
:
&
ServiceDetail
{
TypeMeta
:
common
.
TypeMeta
{
Kind
:
common
.
ResourceKindService
},
PodList
:
pod
.
PodList
{
Pods
:
[]
pod
.
Pod
{}},
},
},
{
service
:
&
api
.
Service
{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test-service"
,
Namespace
:
"test-namespace"
,
}},
namespace
:
"test-namespace"
,
name
:
"test-name"
,
expectedActions
:
[]
string
{
"get"
},
namespace
:
"test-namespace
-2
"
,
name
:
"test-name"
,
expectedActions
:
[]
string
{
"get"
,
"list"
},
expected
:
&
ServiceDetail
{
ObjectMeta
:
common
.
ObjectMeta
{
Name
:
"test-service"
,
...
...
@@ -51,14 +69,16 @@ func TestGetServiceDetail(t *testing.T) {
},
TypeMeta
:
common
.
TypeMeta
{
Kind
:
common
.
ResourceKindService
},
InternalEndpoint
:
common
.
Endpoint
{
Host
:
"test-service.test-namespace"
},
PodList
:
pod
.
PodList
{
Pods
:
[]
pod
.
Pod
{}},
},
},
}
for
_
,
c
:=
range
cases
{
fakeClient
:=
testclient
.
NewSimpleFake
(
c
.
service
)
fakeHeapsterClient
:=
FakeHeapsterClient
{
client
:
testclient
.
NewSimpleFake
()}
actual
,
_
:=
GetServiceDetail
(
fakeClient
,
c
.
namespace
,
c
.
name
)
actual
,
_
:=
GetServiceDetail
(
fakeClient
,
fakeHeapsterClient
,
c
.
namespace
,
c
.
name
)
actions
:=
fakeClient
.
Actions
()
if
len
(
actions
)
!=
len
(
c
.
expectedActions
)
{
...
...
@@ -80,3 +100,72 @@ func TestGetServiceDetail(t *testing.T) {
}
}
}
func
TestGetServicePods
(
t
*
testing
.
T
)
{
firstSelector
:=
map
[
string
]
string
{
"app"
:
"selector-1"
}
secondSelector
:=
map
[
string
]
string
{
"app"
:
"selector-2"
}
cases
:=
[]
struct
{
namespace
string
serviceSelector
map
[
string
]
string
podList
*
api
.
PodList
expectedActions
[]
string
expected
*
pod
.
PodList
}{
{
"test-namespace-1"
,
firstSelector
,
&
api
.
PodList
{
Items
:
[]
api
.
Pod
{}},
[]
string
{
"list"
},
&
pod
.
PodList
{
Pods
:
[]
pod
.
Pod
{}},
},
{
"test-namespace-2"
,
firstSelector
,
&
api
.
PodList
{
Items
:
[]
api
.
Pod
{{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test-pod"
,
Labels
:
secondSelector
,
}}}},
[]
string
{
"list"
},
&
pod
.
PodList
{
Pods
:
[]
pod
.
Pod
{}},
},
{
"test-namespace-3"
,
firstSelector
,
&
api
.
PodList
{
Items
:
[]
api
.
Pod
{{
ObjectMeta
:
api
.
ObjectMeta
{
Name
:
"test-pod"
,
Labels
:
firstSelector
,
Namespace
:
"test-namespace-3"
,
}}}},
[]
string
{
"list"
},
&
pod
.
PodList
{
Pods
:
[]
pod
.
Pod
{{
ObjectMeta
:
common
.
ObjectMeta
{
Name
:
"test-pod"
,
Labels
:
firstSelector
,
Namespace
:
"test-namespace-3"
,
},
TypeMeta
:
common
.
TypeMeta
{
Kind
:
common
.
ResourceKindPod
},
}}},
},
}
for
_
,
c
:=
range
cases
{
fakeClient
:=
testclient
.
NewSimpleFake
(
c
.
podList
)
fakeHeapsterClient
:=
FakeHeapsterClient
{
client
:
testclient
.
NewSimpleFake
()}
actual
,
_
:=
GetServicePods
(
fakeClient
,
fakeHeapsterClient
,
c
.
namespace
,
c
.
serviceSelector
)
actions
:=
fakeClient
.
Actions
()
if
len
(
actions
)
!=
len
(
c
.
expectedActions
)
{
t
.
Errorf
(
"Unexpected actions: %v, expected %d actions got %d"
,
actions
,
len
(
c
.
expectedActions
),
len
(
actions
))
continue
}
for
i
,
verb
:=
range
c
.
expectedActions
{
if
actions
[
i
]
.
GetVerb
()
!=
verb
{
t
.
Errorf
(
"Unexpected action: %+v, expected %s"
,
actions
[
i
],
verb
)
}
}
if
!
reflect
.
DeepEqual
(
actual
,
c
.
expected
)
{
t
.
Errorf
(
"GetServicePods(client, heapsterClient, %#v, %#v) ==
\n
got %#v,
\n
expected %#v"
,
c
.
namespace
,
c
.
serviceSelector
,
actual
,
c
.
expected
)
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录