Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/app/backend/handler/apihandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ func CreateHttpApiHandler(client *client.Client, heapsterClient HeapsterClient,
podsWs.GET("").
To(apiHandler.handleGetPods).
Writes(pod.PodList{}))
podsWs.Route(
podsWs.GET("/{namespace}/{pod}").
To(apiHandler.handleGetPodDetail).
Writes(pod.PodDetail{}))
wsContainer.Add(podsWs)

deploymentsWs := new(restful.WebService)
Expand Down Expand Up @@ -481,6 +485,20 @@ func (apiHandler *ApiHandler) handleGetPods(
response.WriteHeaderAndEntity(http.StatusCreated, result)
}

// Handles get Pod detail API call.
func (apiHandler *ApiHandler) handleGetPodDetail(request *restful.Request, response *restful.Response) {

namespace := request.PathParameter("namespace")
podName := request.PathParameter("pod")
result, err := pod.GetPodDetail(apiHandler.client, apiHandler.heapsterClient, namespace, podName)
if err != nil {
handleInternalError(response, err)
return
}

response.WriteHeaderAndEntity(http.StatusCreated, result)
}

// Handles get Replication Controller detail API call.
func (apiHandler *ApiHandler) handleGetReplicationControllerDetail(
request *restful.Request, response *restful.Response) {
Expand Down
74 changes: 74 additions & 0 deletions src/app/backend/resource/pod/podcommon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 pod

import (
"github.com/kubernetes/dashboard/resource/common"
"k8s.io/kubernetes/pkg/api"
)

// Gets restart count of given pod (total number of its containers restarts).
func getRestartCount(pod api.Pod) int {
restartCount := 0
for _, containerStatus := range pod.Status.ContainerStatuses {
restartCount += containerStatus.RestartCount
}
return restartCount
}

func ToPod(pod *api.Pod, metrics *MetricsByPod) Pod {
podDetail := Pod{
ObjectMeta: common.NewObjectMeta(pod.ObjectMeta),
TypeMeta: common.NewTypeMeta(common.ResourceKindPod),
PodPhase: pod.Status.Phase,
PodIP: pod.Status.PodIP,
RestartCount: getRestartCount(*pod),
}

if metrics != nil && metrics.MetricsMap[pod.Namespace] != nil {
metric := metrics.MetricsMap[pod.Namespace][pod.Name]
podDetail.Metrics = &metric
}

return podDetail
}

func ToPodDetail(pod *api.Pod, metrics *MetricsByPod) PodDetail {
podDetail := PodDetail{
ObjectMeta: common.NewObjectMeta(pod.ObjectMeta),
TypeMeta: common.NewTypeMeta(common.ResourceKindPod),
PodPhase: pod.Status.Phase,
PodIP: pod.Status.PodIP,
RestartCount: getRestartCount(*pod),
ContainerImages: GetContainerImages(&pod.Spec),
NodeName: pod.Spec.NodeName,
}

if metrics != nil && metrics.MetricsMap[pod.Namespace] != nil {
metric := metrics.MetricsMap[pod.Namespace][pod.Name]
podDetail.Metrics = &metric
}

return podDetail
}

// GetContainerImages returns container image strings from the given pod spec.
func GetContainerImages(podTemplate *api.PodSpec) []string {
var containerImages []string
for _, container := range podTemplate.Containers {
containerImages = append(containerImages, container.Image)
}
return containerImages
}
73 changes: 73 additions & 0 deletions src/app/backend/resource/pod/poddetail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 pod

import (
"log"

"k8s.io/kubernetes/pkg/api"
k8sClient "k8s.io/kubernetes/pkg/client/unversioned"

"github.com/kubernetes/dashboard/client"
"github.com/kubernetes/dashboard/resource/common"
)

// PodDetail is a presentation layer view of Kubernetes PodDetail resource.
// This means it is PodDetail plus additional augumented data we can get
// from other sources (like services that target it).
type PodDetail struct {
ObjectMeta common.ObjectMeta `json:"objectMeta"`
TypeMeta common.TypeMeta `json:"typeMeta"`

// Container images of the Pod.
ContainerImages []string `json:"containerImages"`

// Status of the Pod. See Kubernetes API for reference.
PodPhase api.PodPhase `json:"podPhase"`

// IP address of the Pod.
PodIP string `json:"podIP"`

// Name of the Node this Pod runs on.
NodeName string `json:"nodeName"`

// Count of containers restarts.
RestartCount int `json:"restartCount"`

// Pod metrics.
Metrics *PodMetrics `json:"metrics"`
}

// GetPodDetail returns the details (PodDetail) of a named Pod from a particular
// namespace.
func GetPodDetail(client k8sClient.Interface, heapsterClient client.HeapsterClient,
namespace, name string) (*PodDetail, error) {

log.Printf("Getting details of %s pod in %s namespace", name, namespace)

// TODO(floreks): Use channels.
pod, err := client.Pods(namespace).Get(name)
if err != nil {
return nil, err
}

metrics, err := getPodMetrics([]api.Pod{*pod}, heapsterClient)
if err != nil {
log.Printf("Skipping Heapster metrics because of error: %s\n", err)
}

podDetail := ToPodDetail(pod, metrics)
return &podDetail, nil
};
27 changes: 1 addition & 26 deletions src/app/backend/resource/pod/podlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,12 @@ type Pod struct {
ObjectMeta common.ObjectMeta `json:"objectMeta"`
TypeMeta common.TypeMeta `json:"typeMeta"`

// Container images of the Pod.
ContainerImages []string `json:"containerImages"`

// Status of the Pod. See Kubernetes API for reference.
PodPhase api.PodPhase `json:"podPhase"`

// IP address of the Pod.
PodIP string `json:"podIP"`

// Name of the Node this Pod runs on.
NodeName string `json:"nodeName"`

// Count of containers restarts.
RestartCount int `json:"restartCount"`

Expand Down Expand Up @@ -92,28 +86,9 @@ func CreatePodList(pods []api.Pod, heapsterClient client.HeapsterClient) PodList
}

for _, pod := range pods {
podDetail := Pod{
ObjectMeta: common.NewObjectMeta(pod.ObjectMeta),
TypeMeta: common.NewTypeMeta(common.ResourceKindPod),
PodPhase: pod.Status.Phase,
PodIP: pod.Status.PodIP,
RestartCount: getRestartCount(pod),
}
if metrics != nil && metrics.MetricsMap[pod.Namespace] != nil {
metric := metrics.MetricsMap[pod.Namespace][pod.Name]
podDetail.Metrics = &metric
}
podDetail := ToPod(&pod, metrics)
podList.Pods = append(podList.Pods, podDetail)
}

return podList
}

// Gets restart count of given pod (total number of its containers restarts).
func getRestartCount(pod api.Pod) int {
restartCount := 0
for _, containerStatus := range pod.Status.ContainerStatuses {
restartCount += containerStatus.RestartCount
}
return restartCount
}
17 changes: 15 additions & 2 deletions src/app/externs/backendapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,15 +269,28 @@ backendApi.DeleteReplicationControllerSpec;
* @typedef {{
* objectMeta: !backendApi.ObjectMeta,
* typeMeta: !backendApi.TypeMeta,
* status: string,
* podPhase: string,
* podIP: string,
* nodeName: string,
* restartCount: number,
* metrics: backendApi.PodMetrics
* }}
*/
backendApi.Pod;

/**
* @typedef {{
* objectMeta: !backendApi.ObjectMeta,
* typeMeta: !backendApi.TypeMeta,
* containerImages: !Array<string>,
* podPhase: string,
* podIP: string,
* nodeName: string,
* restartCount: number,
* metrics: backendApi.PodMetrics
* }}
*/
backendApi.PodDetail;

/**
* @typedef {{
* objectMeta: !backendApi.ObjectMeta,
Expand Down
4 changes: 4 additions & 0 deletions src/app/frontend/chrome/chrome.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
width: 42px;
}

.kd-middle-ellipsised-link {
display: block;
}

.kd-toolbar {
box-shadow: $whiteframe-shadow-1dp;
height: $toolbar-height-size-base;
Expand Down
2 changes: 2 additions & 0 deletions src/app/frontend/index_module.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import routeConfig from './index_route';
import serviceDetailModule from './servicedetail/servicedetail_module';
import serviceListModule from './servicelist/servicelist_module';
import workloadsModule from './workloads/workloads_module';
import podDetailModule from './poddetail/poddetail_module';

export default angular
.module(
Expand All @@ -54,6 +55,7 @@ export default angular
workloadsModule.name,
serviceDetailModule.name,
serviceListModule.name,
podDetailModule.name,
])
.config(indexConfig)
.config(routeConfig);
25 changes: 25 additions & 0 deletions src/app/frontend/poddetail/poddetail.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
Copyright 2015 Google Inc. All Rights Reserved.

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.
-->

<div layout="column">
<md-content>
<md-tabs md-border-bottom md-dynamic-height>
<md-tab label="Overview">
<kd-pod-info pod="::ctrl.podDetail"></kd-pod-info>
</md-tab>
</md-tabs>
</md-content>
</div>
27 changes: 27 additions & 0 deletions src/app/frontend/poddetail/poddetail_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

/**
* @final
*/
export class PodDetailController {
/**
* @ngInject
* @param {!backendApi.PodDetail} podDetail
*/
constructor(podDetail) {
/** @export {!backendApi.PodDetail} */
this.podDetail = podDetail;
}
}
38 changes: 38 additions & 0 deletions src/app/frontend/poddetail/poddetail_module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

import componentsModule from 'common/components/components_module';
import eventsModule from 'events/events_module';
import filtersModule from 'common/filters/filters_module';
import stateConfig from './poddetail_stateconfig';
import {podInfoComponent} from './podinfo_component';

/**
* Angular module for the Replica Set details view.
*
* The view shows detailed view of a Replica Set.
*/
export default angular
.module(
'kubernetesDashboard.podDetail',
[
'ngMaterial',
'ngResource',
'ui.router',
componentsModule.name,
filtersModule.name,
eventsModule.name,
])
.config(stateConfig)
.component('kdPodInfo', podInfoComponent);
Loading