diff --git a/src/backend/client/client.go b/src/backend/client/client.go index 007195a4d..a65df76ad 100644 --- a/src/backend/client/client.go +++ b/src/backend/client/client.go @@ -150,7 +150,7 @@ func buildCacheController(client *kubernetes.Clientset) *CacheIndexer { go eventInformer.Run(stopCh) // create the endpoint watcher - endpointsListWatcher := kcache.NewListWatchFromClient(client.CoreV1().RESTClient(), "endpoint", v1.NamespaceAll, fields.Everything()) + endpointsListWatcher := kcache.NewListWatchFromClient(client.CoreV1().RESTClient(), "endpoints", v1.NamespaceAll, fields.Everything()) endpointsIndexer, endpointsinformer := kcache.NewIndexerInformer(endpointsListWatcher, &v1.Endpoints{}, defaultResyncPeriod, kcache.ResourceEventHandlerFuncs{}, kcache.Indexers{}) go endpointsinformer.Run(stopCh) return &CacheIndexer{ diff --git a/src/backend/controllers/kubernetes/service/service.go b/src/backend/controllers/kubernetes/service/service.go index f000ac0d3..4d3423a78 100644 --- a/src/backend/controllers/kubernetes/service/service.go +++ b/src/backend/controllers/kubernetes/service/service.go @@ -58,7 +58,7 @@ func (c *KubeServiceController) GetDetail() { if err != nil { c.AbortBadRequestFormat("Cluster") } - serviceDetail, err := service.GetServiceDetail(manager.Client, manager.Indexer, namespace, namespace) + serviceDetail, err := service.GetServiceDetail(manager.Client, manager.Indexer, namespace, name) if err != nil { logs.Error("get kubernetes(%s) namespace(%s) service(%s) detail error: %s", cluster, namespace, name, err.Error()) c.AbortInternalServerError("get kubernetes service detail error.") @@ -173,7 +173,7 @@ func (c *KubeServiceController) Get() { name := c.Ctx.Input.Param(":service") cli, err := client.Client(cluster) if err == nil { - result, err := service.GetServiceDetail(cli, name, namespace) + result, err := service.GetService(cli, name, namespace) if err != nil { logs.Error("get kubernetes service detail error.", cluster, namespace, name, err) c.HandleError(err) diff --git a/src/backend/resources/common/endpoint.go b/src/backend/resources/common/endpoint.go new file mode 100644 index 000000000..75a9db478 --- /dev/null +++ b/src/backend/resources/common/endpoint.go @@ -0,0 +1,81 @@ +// Copyright 2017 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 common + +import ( + "bytes" + + api "k8s.io/api/core/v1" +) + +// Endpoint describes an endpoint that is host and a list of available ports for that host. +type Endpoint struct { + // Hostname, either as a domain name or IP address. + Host string `json:"host"` + + // List of ports opened for this endpoint on the hostname. + Ports []ServicePort `json:"ports"` +} + +// GetExternalEndpoints returns endpoints that are externally reachable for a service. +func GetExternalEndpoints(service *api.Service) []Endpoint { + var externalEndpoints []Endpoint + if service.Spec.Type == api.ServiceTypeLoadBalancer { + for _, ingress := range service.Status.LoadBalancer.Ingress { + externalEndpoints = append(externalEndpoints, getExternalEndpoint(ingress, service.Spec.Ports)) + } + } + + for _, ip := range service.Spec.ExternalIPs { + externalEndpoints = append(externalEndpoints, Endpoint{ + Host: ip, + Ports: GetServicePorts(service.Spec.Ports), + }) + } + + return externalEndpoints +} + +// GetInternalEndpoint returns internal endpoint name for the given service properties, e.g., +// "my-service.namespace 80/TCP" or "my-service 53/TCP,53/UDP". +func GetInternalEndpoint(serviceName, namespace string, ports []api.ServicePort) Endpoint { + name := serviceName + + if namespace != api.NamespaceDefault && len(namespace) > 0 && len(serviceName) > 0 { + bufferName := bytes.NewBufferString(name) + bufferName.WriteString(".") + bufferName.WriteString(namespace) + name = bufferName.String() + } + + return Endpoint{ + Host: name, + Ports: GetServicePorts(ports), + } +} + +// Returns external endpoint name for the given service properties. +func getExternalEndpoint(ingress api.LoadBalancerIngress, ports []api.ServicePort) Endpoint { + var host string + if ingress.Hostname != "" { + host = ingress.Hostname + } else { + host = ingress.IP + } + return Endpoint{ + Host: host, + Ports: GetServicePorts(ports), + } +} diff --git a/src/backend/resources/common/serviceport.go b/src/backend/resources/common/serviceport.go new file mode 100644 index 000000000..705f2a1b4 --- /dev/null +++ b/src/backend/resources/common/serviceport.go @@ -0,0 +1,38 @@ +// Copyright 2017 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 common + +import api "k8s.io/api/core/v1" + +// ServicePort is a pair of port and protocol, e.g. a service endpoint. +type ServicePort struct { + // Positive port number. + Port int32 `json:"port"` + + // Protocol name, e.g., TCP or UDP. + Protocol api.Protocol `json:"protocol"` + + // The port on each node on which service is exposed. + NodePort int32 `json:"nodePort"` +} + +// GetServicePorts returns human readable name for the given service ports list. +func GetServicePorts(apiPorts []api.ServicePort) []ServicePort { + var ports []ServicePort + for _, port := range apiPorts { + ports = append(ports, ServicePort{port.Port, port.Protocol, port.NodePort}) + } + return ports +} diff --git a/src/backend/resources/common/types.go b/src/backend/resources/common/types.go index e65ef5a45..b17598f16 100644 --- a/src/backend/resources/common/types.go +++ b/src/backend/resources/common/types.go @@ -64,3 +64,10 @@ func NewObjectMeta(k8SObjectMeta metaV1.ObjectMeta) ObjectMeta { Annotations: k8SObjectMeta.Annotations, } } + +// NewTypeMeta creates new type mete for the resource kind. +func NewTypeMeta(kind ResourceKind) TypeMeta { + return TypeMeta{ + Kind: kind, + } +} diff --git a/src/backend/resources/service/detail.go b/src/backend/resources/service/detail.go index 40ab06e96..370ba5c1d 100644 --- a/src/backend/resources/service/detail.go +++ b/src/backend/resources/service/detail.go @@ -41,7 +41,7 @@ type ServiceDetail struct { EventList []common.Event `json:"eventList"` // PodInfos represents list of pods status targeted by same label selector as this service. - PodLists []v1.Pod `json:"podInfos"` + PodList []v1.Pod `json:"podList"` // Show the value of the SessionAffinity of the Service. SessionAffinity v1.ServiceAffinity `json:"sessionAffinity"` @@ -76,7 +76,7 @@ func toServiceDetail(service *v1.Service, events []common.Event, pods []v1.Pod, ClusterIP: service.Spec.ClusterIP, Type: service.Spec.Type, EventList: events, - PodLists: pods, + PodList: pods, SessionAffinity: service.Spec.SessionAffinity, } } diff --git a/src/backend/resources/service/service.go b/src/backend/resources/service/service.go index 8df3eb764..350907d1a 100644 --- a/src/backend/resources/service/service.go +++ b/src/backend/resources/service/service.go @@ -23,7 +23,7 @@ func CreateOrUpdateService(cli *kubernetes.Clientset, service *kapi.Service) (*k return cli.CoreV1().Services(service.Namespace).Update(old) } -func GetServiceDetail(cli *kubernetes.Clientset, name, namespace string) (*kapi.Service, error) { +func GetService(cli *kubernetes.Clientset, name, namespace string) (*kapi.Service, error) { service, err := cli.CoreV1().Services(namespace).Get(name, metaV1.GetOptions{}) if err != nil { return nil, err diff --git a/src/backend/routers/commentsRouter_controllers_kubernetes_service.go b/src/backend/routers/commentsRouter_controllers_kubernetes_service.go index 9cc2505c0..7df12bec9 100644 --- a/src/backend/routers/commentsRouter_controllers_kubernetes_service.go +++ b/src/backend/routers/commentsRouter_controllers_kubernetes_service.go @@ -7,6 +7,14 @@ import ( func init() { + beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"], + beego.ControllerComments{ + Method: "GetDetail", + Router: `/:service/detail/namespaces/:namespace/clusters/:cluster`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"], beego.ControllerComments{ Method: "Get", @@ -31,4 +39,12 @@ func init() { MethodParams: param.Make(), Params: nil}) + beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/kubernetes/service:KubeServiceController"], + beego.ControllerComments{ + Method: "List", + Router: `/namespaces/:namespace/clusters/:cluster`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Params: nil}) + }