replicationcontrollerdetail.go 11.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// 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 main

import (
18
	"bytes"
M
Marcin Maciaszczyk 已提交
19 20
	"log"

21
	"k8s.io/kubernetes/pkg/api"
22
	unversioned "k8s.io/kubernetes/pkg/api/unversioned"
23
	client "k8s.io/kubernetes/pkg/client/unversioned"
24 25
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
26 27
)

28 29 30
// ReplicationControllerDetail represents detailed information about a Replication Controller.
type ReplicationControllerDetail struct {
	// Name of the Replication Controller.
31 32
	Name string `json:"name"`

33
	// Namespace the Replication Controller is in.
34 35
	Namespace string `json:"namespace"`

36
	// Label mapping of the Replication Controller.
37 38
	Labels map[string]string `json:"labels"`

39
	// Label selector of the Replication Controller.
40 41
	LabelSelector map[string]string `json:"labelSelector"`

42
	// Container image list of the pod template specified by this Replication Controller.
43 44
	ContainerImages []string `json:"containerImages"`

45 46
	// Aggregate information about pods of this replication controller.
	PodInfo ReplicationControllerPodInfo `json:"podInfo"`
47

48 49
	// Detailed information about Pods belonging to this Replication Controller.
	Pods []ReplicationControllerPod `json:"pods"`
50

51
	// Detailed information about service related to Replication Controller.
52
	Services []ServiceDetail `json:"services"`
53 54 55

	// True when the data contains at least one pod with metrics information, false otherwise.
	HasMetrics bool `json:"hasMetrics"`
56 57
}

58 59
// Detailed information about a Pod that belongs to a Replication Controller.
type ReplicationControllerPod struct {
60 61 62
	// Name of the Pod.
	Name string `json:"name"`

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

66 67 68 69 70 71 72 73
	// Time the Pod has started. Empty if not started.
	StartTime *unversioned.Time `json:"startTime"`

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

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

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

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

82
// Detailed information about a Service connected to Replication Controller.
83
type ServiceDetail struct {
84 85 86
	// Name of the service.
	Name string `json:"name"`

87
	// Internal endpoints of all Kubernetes services that have the same label selector as connected
88
	// Replication Controller.
89
	// Endpoint is DNS name merged with ports.
90
	InternalEndpoint Endpoint `json:"internalEndpoint"`
91 92

	// External endpoints of all Kubernetes services that have the same label selector as connected
93
	// Replication Controller.
94
	// Endpoint is external IP address name merged with ports.
95
	ExternalEndpoints []Endpoint `json:"externalEndpoints"`
96 97 98 99 100

	// Label selector of the service.
	Selector map[string]string `json:"selector"`
}

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
// Port and protocol pair of, e.g., a service endpoint.
type ServicePort struct {
	// Positive port number.
	Port int `json:"port"`

	// Protocol name, e.g., TCP or UDP.
	Protocol api.Protocol `json:"protocol"`
}

// 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"`
}

119 120
// Information needed to update replication controller
type ReplicationControllerSpec struct {
121 122 123 124
	// Replicas (pods) number in replicas set
	Replicas int `json:"replicas"`
}

125 126 127 128
// Returns detailed information about the given replication controller in the given namespace.
func GetReplicationControllerDetail(client client.Interface, heapsterClient HeapsterClient,
	namespace, name string) (*ReplicationControllerDetail, error) {
	log.Printf("Getting details of %s replication controller in %s namespace", name, namespace)
129

130
	replicationControllerWithPods, err := getRawReplicationControllerWithPods(client, namespace, name)
131 132 133
	if err != nil {
		return nil, err
	}
134 135
	replicationController := replicationControllerWithPods.ReplicationController
	pods := replicationControllerWithPods.Pods
136

137
	replicationControllerMetricsByPod, err := getReplicationControllerPodsMetrics(pods, heapsterClient, namespace, name)
138
	if err != nil {
139
		log.Printf("Skipping Heapster metrics because of error: %s\n", err)
140 141
	}

142 143 144 145 146 147 148 149 150
	services, err := client.Services(namespace).List(unversioned.ListOptions{
		LabelSelector: unversioned.LabelSelector{labels.Everything()},
		FieldSelector: unversioned.FieldSelector{fields.Everything()},
	})

	if err != nil {
		return nil, err
	}

151 152 153 154 155 156
	replicationControllerDetail := &ReplicationControllerDetail{
		Name:          replicationController.Name,
		Namespace:     replicationController.Namespace,
		Labels:        replicationController.ObjectMeta.Labels,
		LabelSelector: replicationController.Spec.Selector,
		PodInfo:       getReplicationControllerPodInfo(replicationController, pods.Items),
157 158
	}

159
	matchingServices := getMatchingServices(services.Items, replicationController)
160 161

	for _, service := range matchingServices {
162
		replicationControllerDetail.Services = append(replicationControllerDetail.Services, getServiceDetail(service))
163 164
	}

165 166
	for _, container := range replicationController.Spec.Template.Spec.Containers {
		replicationControllerDetail.ContainerImages = append(replicationControllerDetail.ContainerImages, container.Image)
167 168 169
	}

	for _, pod := range pods.Items {
170
		podDetail := ReplicationControllerPod{
171
			Name:         pod.Name,
172
			PodPhase:     pod.Status.Phase,
173 174 175 176
			StartTime:    pod.Status.StartTime,
			PodIP:        pod.Status.PodIP,
			NodeName:     pod.Spec.NodeName,
			RestartCount: getRestartCount(pod),
177
		}
178 179
		if replicationControllerMetricsByPod != nil {
			metric := replicationControllerMetricsByPod.MetricsMap[pod.Name]
180
			podDetail.Metrics = &metric
181
			replicationControllerDetail.HasMetrics = true
182
		}
183
		replicationControllerDetail.Pods = append(replicationControllerDetail.Pods, podDetail)
184 185
	}

186
	return replicationControllerDetail, nil
187
}
188

189 190 191 192 193 194
// TODO(floreks): This should be transactional to make sure that RC will not be deleted without pods
// Deletes replication controller with given name in given namespace and related pods.
// Also deletes services related to replication controller if deleteServices is true.
func DeleteReplicationController(client client.Interface, namespace, name string,
	deleteServices bool) error {

195
	log.Printf("Deleting %s replication controller from %s namespace", name, namespace)
M
Marcin Maciaszczyk 已提交
196

197 198 199 200 201 202
	if deleteServices {
		if err := DeleteReplicationControllerServices(client, namespace, name); err != nil {
			return err
		}
	}

203
	pods, err := getRawReplicationControllerPods(client, namespace, name)
204 205 206 207 208 209 210 211 212 213 214 215 216 217
	if err != nil {
		return err
	}

	if err := client.ReplicationControllers(namespace).Delete(name); err != nil {
		return err
	}

	for _, pod := range pods.Items {
		if err := client.Pods(namespace).Delete(pod.Name, &api.DeleteOptions{}); err != nil {
			return err
		}
	}

218
	log.Printf("Successfully deleted %s replication controller from %s namespace", name, namespace)
M
Marcin Maciaszczyk 已提交
219

220 221 222
	return nil
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
// Deletes services related to replication controller with given name in given namespace.
func DeleteReplicationControllerServices(client client.Interface, namespace, name string) error {
	log.Printf("Deleting services related to %s replication controller from %s namespace", name,
		namespace)

	replicationController, err := client.ReplicationControllers(namespace).Get(name)
	if err != nil {
		return err
	}

	labelSelector, err := toLabelSelector(replicationController.Spec.Selector)
	if err != nil {
		return err
	}

	services, err := getServicesForDeletion(client, labelSelector, namespace)
	if err != nil {
		return err
	}

	for _, service := range services {
		if err := client.Services(namespace).Delete(service.Name); err != nil {
			return err
		}
	}

	log.Printf("Successfully deleted services related to %s replication controller from %s namespace",
		name, namespace)

	return nil
}

255
// Updates number of replicas in Replication Controller based on Replication Controller Spec
M
Marcin Maciaszczyk 已提交
256
func UpdateReplicasCount(client client.Interface, namespace, name string,
257 258 259
	replicationControllerSpec *ReplicationControllerSpec) error {
	log.Printf("Updating replicas count to %d for %s replication controller from %s namespace",
		replicationControllerSpec.Replicas, name, namespace)
M
Marcin Maciaszczyk 已提交
260

261
	replicationController, err := client.ReplicationControllers(namespace).Get(name)
262 263 264 265
	if err != nil {
		return err
	}

266
	replicationController.Spec.Replicas = replicationControllerSpec.Replicas
267

268
	_, err = client.ReplicationControllers(namespace).Update(replicationController)
269 270 271 272
	if err != nil {
		return err
	}

273 274
	log.Printf("Successfully updated replicas count to %d for %s replication controller from %s namespace",
		replicationControllerSpec.Replicas, name, namespace)
M
Marcin Maciaszczyk 已提交
275

276 277 278
	return nil
}

279
// Returns detailed information about service from given service
280
func getServiceDetail(service api.Service) ServiceDetail {
281
	var externalEndpoints []Endpoint
282 283
	for _, externalIp := range service.Status.LoadBalancer.Ingress {
		externalEndpoints = append(externalEndpoints,
284
			getExternalEndpoint(externalIp, service.Spec.Ports))
285 286 287
	}

	serviceDetail := ServiceDetail{
288
		Name: service.ObjectMeta.Name,
289 290 291 292 293 294 295 296
		InternalEndpoint: getInternalEndpoint(service.Name, service.Namespace,
			service.Spec.Ports),
		ExternalEndpoints: externalEndpoints,
		Selector:          service.Spec.Selector,
	}

	return serviceDetail
}
297 298 299 300 301 302 303 304 305

// 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
}
306 307 308

// Returns internal endpoint name for the given service properties, e.g.,
// "my-service.namespace 80/TCP" or "my-service 53/TCP,53/UDP".
M
Marcin Maciaszczyk 已提交
309
func getInternalEndpoint(serviceName, namespace string, ports []api.ServicePort) Endpoint {
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

	name := serviceName
	if namespace != api.NamespaceDefault {
		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),
	}
}

// Gets 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})
	}
	return ports
}