replicasetlist.go 6.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 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 (
	"k8s.io/kubernetes/pkg/api"
19
	"k8s.io/kubernetes/pkg/api/unversioned"
20 21 22
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
23 24
	"strconv"
	"strings"
25 26
)

27 28 29 30
// List of Replica Sets in the cluster.
type ReplicaSetList struct {
	// Unordered list of Replica Sets.
	ReplicaSets []ReplicaSet `json:"replicaSets"`
31 32
}

33 34 35 36
// Kubernetes Replica Set (aka. Replication Controller) plus zero or more Kubernetes services that
// target the Replica Set.
type ReplicaSet struct {
	// Name of the Replica Set.
37 38
	Name string `json:"name"`

39 40 41
	// Namespace this Replica Set is in.
	Namespace string `json:"namespace"`

42 43 44 45 46 47
	// Human readable description of this Replica Set.
	Description string `json:"description"`

	// Label of this Replica Set.
	Labels map[string]string `json:"labels"`

48 49 50
	// Number of pods that are currently running.
	PodsRunning int `json:"podsRunning"`

51 52
	// Number of pods that are pending in this Replica Set.
	PodsPending int `json:"podsPending"`
53

54
	// Container images of the Replica Set.
55
	ContainerImages []string `json:"containerImages"`
56

57 58
	// Time the replica set was created.
	CreationTime unversioned.Time `json:"creationTime"`
59 60

	// Internal endpoints of all Kubernetes services have the same label selector as this Replica Set.
61
	// Endpoint is DNS name merged with ports.
62 63 64
	InternalEndpoints []string `json:"internalEndpoints"`

	// External endpoints of all Kubernetes services have the same label selector as this Replica Set.
65
	// Endpoint is external IP address name merged with ports.
66
	ExternalEndpoints []string `json:"externalEndpoints"`
67 68
}

69 70
// Returns a list of all Replica Sets in the cluster.
func GetReplicaSetList(client *client.Client) (*ReplicaSetList, error) {
71
	replicaSets, err := client.ReplicationControllers(api.NamespaceAll).
72 73 74 75 76 77
		List(labels.Everything(), fields.Everything())

	if err != nil {
		return nil, err
	}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	services, err := client.Services(api.NamespaceAll).
		List(labels.Everything(), fields.Everything())

	if err != nil {
		return nil, err
	}

	return getReplicaSetList(replicaSets.Items, services.Items), nil
}

// Returns a list of all Replica Set model objects in the cluster, based on all Kubernetes
// Replica Set and Service API objects.
// The function processes all Replica Sets API objects and finds matching Services for them.
func getReplicaSetList(
	replicaSets []api.ReplicationController, services []api.Service) *ReplicaSetList {

94
	replicaSetList := &ReplicaSetList{}
95

96
	for _, replicaSet := range replicaSets {
97
		var containerImages []string
98
		for _, container := range replicaSet.Spec.Template.Spec.Containers {
99 100 101
			containerImages = append(containerImages, container.Image)
		}

102 103 104 105 106 107 108 109 110 111 112 113
		matchingServices := getMatchingServices(services, &replicaSet)
		var internalEndpoints []string
		var externalEndpoints []string
		for _, service := range matchingServices {
			internalEndpoints = append(internalEndpoints,
				getInternalEndpoint(service.Name, service.Namespace, service.Spec.Ports))
			for _, externalIp := range service.Status.LoadBalancer.Ingress {
				externalEndpoints = append(externalEndpoints,
					getExternalEndpoint(externalIp.Hostname, service.Spec.Ports))
			}
		}

114
		replicaSetList.ReplicaSets = append(replicaSetList.ReplicaSets, ReplicaSet{
115 116 117 118 119 120 121 122 123 124
			Name:              replicaSet.ObjectMeta.Name,
			Namespace:         replicaSet.ObjectMeta.Namespace,
			Description:       replicaSet.Annotations[DescriptionAnnotationKey],
			Labels:            replicaSet.ObjectMeta.Labels,
			PodsRunning:       replicaSet.Status.Replicas,
			PodsPending:       replicaSet.Spec.Replicas - replicaSet.Status.Replicas,
			ContainerImages:   containerImages,
			CreationTime:      replicaSet.ObjectMeta.CreationTimestamp,
			InternalEndpoints: internalEndpoints,
			ExternalEndpoints: externalEndpoints,
125 126 127
		})
	}

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	return replicaSetList
}

// 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 string, namespace string, ports []api.ServicePort) string {
	name := serviceName
	if namespace != api.NamespaceDefault {
		name = name + "." + namespace
	}

	return name + getServicePortsName(ports)
}

// Returns external endpoint name for the given service properties.
func getExternalEndpoint(serviceIp string, ports []api.ServicePort) string {
	return serviceIp + getServicePortsName(ports)
}

// Gets human readable name for the given service ports list.
func getServicePortsName(ports []api.ServicePort) string {
	var portsString []string
	for _, port := range ports {
		portsString = append(portsString, strconv.Itoa(port.Port)+"/"+string(port.Protocol))
	}
	if len(portsString) > 0 {
		return " " + strings.Join(portsString, ",")
	} else {
		return ""
	}
}

// Returns all services that target the same Pods (or subset) as the given Replica Set.
func getMatchingServices(services []api.Service,
	replicaSet *api.ReplicationController) []api.Service {

	var matchingServices []api.Service
	for _, service := range services {
		if isServiceMatchingReplicaSet(service.Spec.Selector, replicaSet.Spec.Selector) {
			matchingServices = append(matchingServices, service)
		}
	}
	return matchingServices
}

// Returns true when a Service with the given selector targets the same Pods (or subset) that
// a Replica Set with the given selector.
func isServiceMatchingReplicaSet(serviceSelector map[string]string,
	replicaSetSpecSelector map[string]string) bool {

	// If service has no selectors, then assume it targets different Pods.
	if len(serviceSelector) == 0 {
		return false
	}
	for label, value := range serviceSelector {
		if rsValue, ok := replicaSetSpecSelector[label]; !ok || rsValue != value {
			return false
		}
	}
	return true
188
}