diff --git a/api/doc/controller-schema.json b/api/doc/controller-schema.json
index 7baa0eb944..bec1d9ac1c 100644
--- a/api/doc/controller-schema.json
+++ b/api/doc/controller-schema.json
@@ -30,7 +30,7 @@
"required": false,
"description": "Number of pods desired in the set"
},
- "replicasInSet": {
+ "replicaSelector": {
"type": "object",
"required": false,
"description": "Required labels used to identify pods in the set"
diff --git a/api/doc/service-schema.json b/api/doc/service-schema.json
index 0f85b40ac9..f5a8aba95f 100644
--- a/api/doc/service-schema.json
+++ b/api/doc/service-schema.json
@@ -32,5 +32,9 @@
"type": "object",
"required": false
}
+ "selector": {
+ "type": "object",
+ "required": false
+ }
}
}
diff --git a/api/examples/controller-list.json b/api/examples/controller-list.json
index b2a17950b4..3631770957 100644
--- a/api/examples/controller-list.json
+++ b/api/examples/controller-list.json
@@ -4,7 +4,7 @@
"id": "testRun",
"desiredState": {
"replicas": 2,
- "replicasInSet": {
+ "replicaSelector": {
"name": "testRun"
},
"podTemplate": {
diff --git a/api/examples/controller.json b/api/examples/controller.json
index c08be4aaae..8b6da66ca8 100644
--- a/api/examples/controller.json
+++ b/api/examples/controller.json
@@ -2,7 +2,7 @@
"id": "nginxController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "nginx"},
+ "replicaSelector": {"name": "nginx"},
"podTemplate": {
"desiredState": {
"manifest": {
diff --git a/api/examples/external-service.json b/api/examples/external-service.json
index e3f1d437ce..e841b2e946 100644
--- a/api/examples/external-service.json
+++ b/api/examples/external-service.json
@@ -4,5 +4,8 @@
"labels": {
"name": "nginx"
},
+ "selector": {
+ "name": "nginx"
+ },
"createExternalLoadBalancer": true
}
diff --git a/api/examples/service-list.json b/api/examples/service-list.json
index 5fe2e8461c..2d9dea5129 100644
--- a/api/examples/service-list.json
+++ b/api/examples/service-list.json
@@ -6,6 +6,9 @@
"labels": {
"name": "nginx"
}
+ "selector": {
+ "name": "nginx"
+ }
},
{
"id": "example2",
@@ -14,6 +17,10 @@
"env": "prod",
"name": "jetty"
}
+ "selector": {
+ "env": "prod",
+ "name": "jetty"
+ }
}
]
}
diff --git a/api/examples/service.json b/api/examples/service.json
index 68012f4459..f194aea41e 100644
--- a/api/examples/service.json
+++ b/api/examples/service.json
@@ -4,4 +4,7 @@
"labels": {
"name": "nginx"
}
+ "selector": {
+ "name": "nginx"
+ }
}
diff --git a/api/kubernetes.html b/api/kubernetes.html
index 8678ab0ad0..b6cfcae98f 100644
--- a/api/kubernetes.html
+++ b/api/kubernetes.html
@@ -970,7 +970,7 @@ implemented, either.
"id": "testRun",
"desiredState": {
"replicas": 2,
- "replicasInSet": {
+ "replicaSelector": {
"name": "testRun"
},
"podTemplate": {
@@ -1074,7 +1074,7 @@ implemented, either.
"required": false,
"description": "Number of pods desired in the set"
},
- "replicasInSet": {
+ "replicaSelector": {
"type": "object",
"required": false,
"description": "Required labels used to identify pods in the set"
@@ -1100,7 +1100,7 @@ implemented, either.
"id": "nginxController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "nginx"},
+ "replicaSelector": {"name": "nginx"},
"podTemplate": {
"desiredState": {
"manifest": {
@@ -1231,7 +1231,7 @@ implemented, either.
"id": "nginxController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "nginx"},
+ "replicaSelector": {"name": "nginx"},
"podTemplate": {
"desiredState": {
"manifest": {
@@ -1333,7 +1333,7 @@ implemented, either.
"required": false,
"description": "Number of pods desired in the set"
},
- "replicasInSet": {
+ "replicaSelector": {
"type": "object",
"required": false,
"description": "Required labels used to identify pods in the set"
@@ -1359,7 +1359,7 @@ implemented, either.
"id": "nginxController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "nginx"},
+ "replicaSelector": {"name": "nginx"},
"podTemplate": {
"desiredState": {
"manifest": {
diff --git a/cmd/cloudcfg/cloudcfg.go b/cmd/cloudcfg/cloudcfg.go
index 99380f84da..2ba1cc3216 100644
--- a/cmd/cloudcfg/cloudcfg.go
+++ b/cmd/cloudcfg/cloudcfg.go
@@ -39,7 +39,7 @@ var (
versionFlag = flag.Bool("v", false, "Print the version number.")
httpServer = flag.String("h", "", "The host to connect to.")
config = flag.String("c", "", "Path to the config file.")
- labelQuery = flag.String("l", "", "Label query to use for listing")
+ selector = flag.String("l", "", "Selector (label query) to use for listing")
updatePeriod = flag.Duration("u", 60*time.Second, "Update interarrival period")
portSpec = flag.String("p", "", "The port spec, comma-separated list of :,...")
servicePort = flag.Int("s", -1, "If positive, create and run a corresponding service on this port, only used with 'run'")
@@ -143,8 +143,8 @@ func executeAPIRequest(method string, auth *kube_client.AuthInfo) bool {
switch method {
case "get", "list":
url := readUrl(parseStorage())
- if len(*labelQuery) > 0 && method == "list" {
- url = url + "?labels=" + *labelQuery
+ if len(*selector) > 0 && method == "list" {
+ url = url + "?labels=" + *selector
}
request, err = http.NewRequest("GET", url, nil)
case "delete":
diff --git a/examples/guestbook/frontend-controller.json b/examples/guestbook/frontend-controller.json
index f3c94ea496..e7caab32ac 100644
--- a/examples/guestbook/frontend-controller.json
+++ b/examples/guestbook/frontend-controller.json
@@ -2,7 +2,7 @@
"id": "frontendController",
"desiredState": {
"replicas": 1,
- "replicasInSet": {"name": "frontend"},
+ "replicaSelector": {"name": "frontend"},
"podTemplate": {
"desiredState": {
"manifest": {
diff --git a/examples/guestbook/guestbook.md b/examples/guestbook/guestbook.md
index 8ab6e84640..53d5051754 100644
--- a/examples/guestbook/guestbook.md
+++ b/examples/guestbook/guestbook.md
@@ -73,18 +73,20 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
### Step Two: Turn up the master service.
A Kubernetes 'service' is a named load balancer that proxies traffic to one or more containers. The services in a Kubernetes cluster are discoverable inside other containers via environment variables. Services find the containers to load balance based on pod labels.
-The pod that you created in Step One has the label `name=redis-master`, so the corresponding service is defined by that label. Create a file named `redis-master-service.json` that contains:
+The pod that you created in Step One has the label `name=redis-master`. The selector field of the service determines which pods will receive the traffic sent to the service. Create a file named `redis-master-service.json` that contains:
```js
{
"id": "redismaster",
"port": 10000,
- "labels": {
+ "selector": {
"name": "redis-master"
}
}
```
+This will cause all pods to see the redis master apparently running on localhost:10000.
+
Once you have that service description, you can create the service with the `cloudcfg` cli:
```shell
@@ -106,7 +108,7 @@ Create a file named `redis-slave-controller.json` that contains:
"id": "redisSlaveController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "redis-slave"},
+ "replicaSelector": {"name": "redis-slave"},
"podTemplate": {
"desiredState": {
"manifest": {
@@ -126,7 +128,7 @@ Then you can create the service by running:
```shell
$ cluster/cloudcfg.sh -c examples/guestbook/redis-slave-controller.json create /replicationControllers
-Name Image(s) Label Query Replicas
+Name Image(s) Selector Replicas
---------- ---------- ---------- ----------
redisSlaveController brendanburns/redis-slave name=redisslave 2
```
@@ -160,11 +162,14 @@ Just like the master, we want to have a service to proxy connections to the read
"port": 10001,
"labels": {
"name": "redis-slave"
+ },
+ "selector": {
+ "name": "redis-slave"
}
}
```
-This time the label query for the service is `name=redis-slave`.
+This time the selector for the service is `name=redis-slave`, because that identifies the pods running redis slaves. It may also be helpful to set labels on your service itself--as we've done here--to make it easy to locate them with the `cloudcfg -l "label=value" list sevices` command.
Now that you have created the service specification, create it in your cluster with the `cloudcfg` CLI:
@@ -186,7 +191,7 @@ Create a file named `frontend-controller.json`:
"id": "frontendController",
"desiredState": {
"replicas": 3,
- "replicasInSet": {"name": "frontend"},
+ "replicaSelector": {"name": "frontend"},
"podTemplate": {
"desiredState": {
"manifest": {
@@ -206,7 +211,7 @@ With this file, you can turn up your frontend with:
```shell
$ cluster/cloudcfg.sh -c examples/guestbook/frontend-controller.json create /replicationControllers
-Name Image(s) Label Query Replicas
+Name Image(s) Selector Replicas
---------- ---------- ---------- ----------
frontendController brendanburns/php-redis name=frontend 3
```
diff --git a/examples/guestbook/redis-master-service.json b/examples/guestbook/redis-master-service.json
index 654c7e9307..5d79ea37fd 100644
--- a/examples/guestbook/redis-master-service.json
+++ b/examples/guestbook/redis-master-service.json
@@ -1,7 +1,7 @@
{
"id": "redismaster",
"port": 10000,
- "labels": {
+ "selector": {
"name": "redis-master"
}
}
diff --git a/examples/guestbook/redis-slave-controller.json b/examples/guestbook/redis-slave-controller.json
index ee6a31e0da..d4d38117c2 100644
--- a/examples/guestbook/redis-slave-controller.json
+++ b/examples/guestbook/redis-slave-controller.json
@@ -2,7 +2,7 @@
"id": "redisSlaveController",
"desiredState": {
"replicas": 2,
- "replicasInSet": {"name": "redisslave"},
+ "replicaSelector": {"name": "redisslave"},
"podTemplate": {
"desiredState": {
"manifest": {
diff --git a/examples/guestbook/redis-slave-service.json b/examples/guestbook/redis-slave-service.json
index d9e30f8363..ee87e91252 100644
--- a/examples/guestbook/redis-slave-service.json
+++ b/examples/guestbook/redis-slave-service.json
@@ -4,4 +4,7 @@
"labels": {
"name": "redisslave"
}
+ "selector": {
+ "name": "redisslave"
+ }
}
diff --git a/pkg/api/types.go b/pkg/api/types.go
index 0c7ea04a75..29a71cde7c 100644
--- a/pkg/api/types.go
+++ b/pkg/api/types.go
@@ -108,9 +108,9 @@ type Pod struct {
// ReplicationControllerState is the state of a replication controller, either input (create, update) or as output (list, get)
type ReplicationControllerState struct {
- Replicas int `json:"replicas" yaml:"replicas"`
- ReplicasInSet map[string]string `json:"replicasInSet,omitempty" yaml:"replicasInSet,omitempty"`
- PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
+ Replicas int `json:"replicas" yaml:"replicas"`
+ ReplicaSelector map[string]string `json:"replicaSelector,omitempty" yaml:"replicaSelector,omitempty"`
+ PodTemplate PodTemplate `json:"podTemplate,omitempty" yaml:"podTemplate,omitempty"`
}
type ReplicationControllerList struct {
@@ -138,11 +138,17 @@ type ServiceList struct {
}
// Defines a service abstraction by a name (for example, mysql) consisting of local port
-// (for example 3306) that the proxy listens on, and the labels that define the service.
+// (for example 3306) that the proxy listens on, and the selector that determines which pods
+// will answer requests sent through the proxy.
type Service struct {
- JSONBase `json:",inline" yaml:",inline"`
- Port int `json:"port,omitempty" yaml:"port,omitempty"`
- Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
+ JSONBase `json:",inline" yaml:",inline"`
+ Port int `json:"port,omitempty" yaml:"port,omitempty"`
+
+ // This service's labels.
+ Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"`
+
+ // This service will route traffic to pods having labels matching this selector.
+ Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
}
diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go
index ea58302a0b..c7d638e851 100644
--- a/pkg/apiserver/apiserver.go
+++ b/pkg/apiserver/apiserver.go
@@ -31,7 +31,7 @@ import (
// RESTStorage is a generic interface for RESTful storage services
type RESTStorage interface {
- List(labels.Query) (interface{}, error)
+ List(labels.Selector) (interface{}, error)
Get(id string) (interface{}, error)
Delete(id string) error
Extract(body string) (interface{}, error)
@@ -149,12 +149,12 @@ func (server *ApiServer) handleREST(parts []string, requestUrl *url.URL, req *ht
case "GET":
switch len(parts) {
case 1:
- query, err := labels.ParseQuery(requestUrl.Query().Get("labels"))
+ selector, err := labels.ParseSelector(requestUrl.Query().Get("labels"))
if err != nil {
server.error(err, w)
return
}
- controllers, err := storage.List(query)
+ controllers, err := storage.List(selector)
if err != nil {
server.error(err, w)
return
diff --git a/pkg/apiserver/apiserver_test.go b/pkg/apiserver/apiserver_test.go
index 41197d5b7e..c10ca1939e 100644
--- a/pkg/apiserver/apiserver_test.go
+++ b/pkg/apiserver/apiserver_test.go
@@ -51,7 +51,7 @@ type SimpleRESTStorage struct {
updated Simple
}
-func (storage *SimpleRESTStorage) List(labels.Query) (interface{}, error) {
+func (storage *SimpleRESTStorage) List(labels.Selector) (interface{}, error) {
result := SimpleList{
Items: storage.list,
}
diff --git a/pkg/client/client.go b/pkg/client/client.go
index 90300589d1..3d137b5be3 100644
--- a/pkg/client/client.go
+++ b/pkg/client/client.go
@@ -33,7 +33,7 @@ import (
// ClientInterface holds the methods for clients of Kubenetes, an interface to allow mock testing
type ClientInterface interface {
- ListPods(labelQuery map[string]string) (api.PodList, error)
+ ListPods(selector map[string]string) (api.PodList, error)
GetPod(name string) (api.Pod, error)
DeletePod(name string) error
CreatePod(api.Pod) (api.Pod, error)
@@ -112,40 +112,40 @@ func (client Client) makeURL(path string) string {
return client.Host + "/api/v1beta1/" + path
}
-// EncodeLabelQuery transforms a label query expressed as a key/value map, into a
+// EncodeSelector transforms a selector expressed as a key/value map, into a
// comma separated, key=value encoding.
-func EncodeLabelQuery(labelQuery map[string]string) string {
- query := make([]string, 0, len(labelQuery))
- for key, value := range labelQuery {
- query = append(query, key+"="+value)
+func EncodeSelector(selector map[string]string) string {
+ parts := make([]string, 0, len(selector))
+ for key, value := range selector {
+ parts = append(parts, key+"="+value)
}
- return url.QueryEscape(strings.Join(query, ","))
+ return url.QueryEscape(strings.Join(parts, ","))
}
-// DecodeLabelQuery transforms a label query from a comma separated, key=value format into
+// DecodeSelector transforms a selector from a comma separated, key=value format into
// a key/value map.
-func DecodeLabelQuery(labelQuery string) map[string]string {
+func DecodeSelector(selector string) map[string]string {
result := map[string]string{}
- if len(labelQuery) == 0 {
+ if len(selector) == 0 {
return result
}
- parts := strings.Split(labelQuery, ",")
+ parts := strings.Split(selector, ",")
for _, part := range parts {
pieces := strings.Split(part, "=")
if len(pieces) == 2 {
result[pieces[0]] = pieces[1]
} else {
- log.Printf("Invalid label query: %s", labelQuery)
+ log.Printf("Invalid selector: %s", selector)
}
}
return result
}
-// ListPods takes a label query, and returns the list of pods that match that query
-func (client Client) ListPods(labelQuery map[string]string) (api.PodList, error) {
+// ListPods takes a selector, and returns the list of pods that match that selector
+func (client Client) ListPods(selector map[string]string) (api.PodList, error) {
path := "pods"
- if labelQuery != nil && len(labelQuery) > 0 {
- path += "?labels=" + EncodeLabelQuery(labelQuery)
+ if selector != nil && len(selector) > 0 {
+ path += "?labels=" + EncodeSelector(selector)
}
var result api.PodList
_, err := client.rawRequest("GET", path, nil, &result)
diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go
index 9cd7cf404f..4b08f34e23 100644
--- a/pkg/client/client_test.go
+++ b/pkg/client/client_test.go
@@ -117,13 +117,13 @@ func TestListPodsLabels(t *testing.T) {
client := Client{
Host: testServer.URL,
}
- query := map[string]string{"foo": "bar", "name": "baz"}
- receivedPodList, err := client.ListPods(query)
+ selector := map[string]string{"foo": "bar", "name": "baz"}
+ receivedPodList, err := client.ListPods(selector)
fakeHandler.ValidateRequest(t, makeUrl("/pods"), "GET", nil)
- queryString := fakeHandler.RequestReceived.URL.Query().Get("labels")
- queryString, _ = url.QueryUnescape(queryString)
- parsedQueryString := DecodeLabelQuery(queryString)
- expectEqual(t, query, parsedQueryString)
+ selectorString := fakeHandler.RequestReceived.URL.Query().Get("labels")
+ selectorString, _ = url.QueryUnescape(selectorString)
+ parsedSelectorString := DecodeSelector(selectorString)
+ expectEqual(t, selector, parsedSelectorString)
if err != nil {
t.Errorf("Unexpected error in listing pods: %#v", err)
}
diff --git a/pkg/cloudcfg/cloudcfg.go b/pkg/cloudcfg/cloudcfg.go
index c1ec9f35cf..fb097703c7 100644
--- a/pkg/cloudcfg/cloudcfg.go
+++ b/pkg/cloudcfg/cloudcfg.go
@@ -74,7 +74,7 @@ func Update(name string, client client.ClientInterface, updatePeriod time.Durati
if err != nil {
return err
}
- labels := controller.DesiredState.ReplicasInSet
+ labels := controller.DesiredState.ReplicaSelector
podList, err := client.ListPods(labels)
if err != nil {
@@ -200,7 +200,7 @@ func RunController(image, name string, replicas int, client client.ClientInterfa
},
DesiredState: api.ReplicationControllerState{
Replicas: replicas,
- ReplicasInSet: map[string]string{
+ ReplicaSelector: map[string]string{
"name": name,
},
PodTemplate: api.PodTemplate{
@@ -255,6 +255,9 @@ func createService(name string, port int, client client.ClientInterface) (api.Se
Labels: map[string]string{
"name": name,
},
+ Selector: map[string]string{
+ "name": name,
+ },
}
svc, err := client.CreateService(svc)
return svc, err
diff --git a/pkg/cloudcfg/cloudcfg_test.go b/pkg/cloudcfg/cloudcfg_test.go
index de23e61216..a1b3ffc089 100644
--- a/pkg/cloudcfg/cloudcfg_test.go
+++ b/pkg/cloudcfg/cloudcfg_test.go
@@ -46,7 +46,7 @@ type FakeKubeClient struct {
ctrl api.ReplicationController
}
-func (client *FakeKubeClient) ListPods(labelQuery map[string]string) (api.PodList, error) {
+func (client *FakeKubeClient) ListPods(selector map[string]string) (api.PodList, error) {
client.actions = append(client.actions, Action{action: "list-pods"})
return client.pods, nil
}
diff --git a/pkg/cloudcfg/parse_test.go b/pkg/cloudcfg/parse_test.go
index 1884466de6..f8ac85b89d 100644
--- a/pkg/cloudcfg/parse_test.go
+++ b/pkg/cloudcfg/parse_test.go
@@ -63,6 +63,9 @@ func TestParseService(t *testing.T) {
Labels: map[string]string{
"area": "staging",
},
+ Selector: map[string]string{
+ "area": "staging",
+ },
})
}
diff --git a/pkg/cloudcfg/resource_printer.go b/pkg/cloudcfg/resource_printer.go
index 74ea104bfe..9368d57d50 100644
--- a/pkg/cloudcfg/resource_printer.go
+++ b/pkg/cloudcfg/resource_printer.go
@@ -24,6 +24,7 @@ import (
"text/tabwriter"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
+ "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"gopkg.in/v1/yaml"
)
@@ -61,8 +62,8 @@ func (y *YAMLPrinter) Print(data string, w io.Writer) error {
type HumanReadablePrinter struct{}
var podColumns = []string{"Name", "Image(s)", "Host", "Labels"}
-var replicationControllerColumns = []string{"Name", "Image(s)", "Label Query", "Replicas"}
-var serviceColumns = []string{"Name", "Label Query", "Port"}
+var replicationControllerColumns = []string{"Name", "Image(s)", "Selector", "Replicas"}
+var serviceColumns = []string{"Name", "Labels", "Selector", "Port"}
func (h *HumanReadablePrinter) unknown(data string, w io.Writer) error {
_, err := fmt.Fprintf(w, "Unknown object: %s", data)
@@ -89,17 +90,9 @@ func (h *HumanReadablePrinter) makeImageList(manifest api.ContainerManifest) str
return strings.Join(images, ",")
}
-func (h *HumanReadablePrinter) makeLabelsList(labels map[string]string) string {
- var vals []string
- for key, value := range labels {
- vals = append(vals, fmt.Sprintf("%s=%s", key, value))
- }
- return strings.Join(vals, ",")
-}
-
func (h *HumanReadablePrinter) printPod(pod api.Pod, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n",
- pod.ID, h.makeImageList(pod.DesiredState.Manifest), pod.CurrentState.Host+"/"+pod.CurrentState.HostIP, h.makeLabelsList(pod.Labels))
+ pod.ID, h.makeImageList(pod.DesiredState.Manifest), pod.CurrentState.Host+"/"+pod.CurrentState.HostIP, labels.Set(pod.Labels))
return err
}
@@ -114,7 +107,7 @@ func (h *HumanReadablePrinter) printPodList(podList api.PodList, w io.Writer) er
func (h *HumanReadablePrinter) printReplicationController(ctrl api.ReplicationController, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n",
- ctrl.ID, h.makeImageList(ctrl.DesiredState.PodTemplate.DesiredState.Manifest), h.makeLabelsList(ctrl.DesiredState.ReplicasInSet), ctrl.DesiredState.Replicas)
+ ctrl.ID, h.makeImageList(ctrl.DesiredState.PodTemplate.DesiredState.Manifest), labels.Set(ctrl.DesiredState.ReplicaSelector), ctrl.DesiredState.Replicas)
return err
}
@@ -128,7 +121,7 @@ func (h *HumanReadablePrinter) printReplicationControllerList(list api.Replicati
}
func (h *HumanReadablePrinter) printService(svc api.Service, w io.Writer) error {
- _, err := fmt.Fprintf(w, "%s\t%s\t%d\n", svc.ID, h.makeLabelsList(svc.Labels), svc.Port)
+ _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n", svc.ID, labels.Set(svc.Labels), labels.Set(svc.Selector), svc.Port)
return err
}
diff --git a/pkg/controller/replication_controller.go b/pkg/controller/replication_controller.go
index 35f6499b9c..a3876f2d48 100644
--- a/pkg/controller/replication_controller.go
+++ b/pkg/controller/replication_controller.go
@@ -177,7 +177,7 @@ func (rm *ReplicationManager) filterActivePods(pods []api.Pod) []api.Pod {
}
func (rm *ReplicationManager) syncReplicationController(controllerSpec api.ReplicationController) error {
- podList, err := rm.kubeClient.ListPods(controllerSpec.DesiredState.ReplicasInSet)
+ podList, err := rm.kubeClient.ListPods(controllerSpec.DesiredState.ReplicaSelector)
if err != nil {
return err
}
diff --git a/pkg/kubelet/kubelet_server.go b/pkg/kubelet/kubelet_server.go
index 9eaf5b8e44..943e0ac20a 100644
--- a/pkg/kubelet/kubelet_server.go
+++ b/pkg/kubelet/kubelet_server.go
@@ -68,7 +68,7 @@ func (s *KubeletServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
container := u.Query().Get("container")
if len(container) == 0 {
w.WriteHeader(http.StatusBadRequest)
- fmt.Fprint(w, "Missing container query arg.")
+ fmt.Fprint(w, "Missing container selector arg.")
return
}
id, found, err := s.Kubelet.GetContainerID(container)
diff --git a/pkg/labels/doc.go b/pkg/labels/doc.go
index 54318e41bb..afc8c27c64 100644
--- a/pkg/labels/doc.go
+++ b/pkg/labels/doc.go
@@ -14,6 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-// Package labels implements a simple label system, parsing and matching queries
-// with sets of labels.
+// Package labels implements a simple label system, parsing and matching
+// selectors with sets of labels.
package labels
diff --git a/pkg/labels/labels.go b/pkg/labels/labels.go
index 156e18561c..351289ea63 100644
--- a/pkg/labels/labels.go
+++ b/pkg/labels/labels.go
@@ -30,18 +30,23 @@ type Labels interface {
type Set map[string]string
// All labels listed as a human readable string. Conveniently, exactly the format
-// that ParseQuery takes.
+// that ParseSelector takes.
func (ls Set) String() string {
- query := make([]string, 0, len(ls))
+ selector := make([]string, 0, len(ls))
for key, value := range ls {
- query = append(query, key+"="+value)
+ selector = append(selector, key+"="+value)
}
// Sort for determinism.
- sort.StringSlice(query).Sort()
- return strings.Join(query, ",")
+ sort.StringSlice(selector).Sort()
+ return strings.Join(selector, ",")
}
// Implement Labels interface.
func (ls Set) Get(label string) string {
return ls[label]
}
+
+// Convenience function: convert these labels to a selector.
+func (ls Set) AsSelector() Selector {
+ return SelectorFromSet(ls)
+}
diff --git a/pkg/labels/query.go b/pkg/labels/query.go
index 5e563924a3..52e712cb3c 100644
--- a/pkg/labels/query.go
+++ b/pkg/labels/query.go
@@ -21,17 +21,17 @@ import (
"strings"
)
-// Represents a label query.
-type Query interface {
- // Returns true if this query matches the given set of labels.
+// Represents a selector.
+type Selector interface {
+ // Returns true if this selector matches the given set of labels.
Matches(Labels) bool
- // Prints a human readable version of this label query.
+ // Prints a human readable version of this selector.
String() string
}
-// Everything returns a query that matches all labels.
-func Everything() Query {
+// Everything returns a selector that matches all labels.
+func Everything() Selector {
return andTerm{}
}
@@ -59,7 +59,7 @@ func (t *notHasTerm) String() string {
return fmt.Sprintf("%v!=%v", t.label, t.value)
}
-type andTerm []Query
+type andTerm []Selector
func (t andTerm) Matches(ls Labels) bool {
for _, q := range t {
@@ -78,17 +78,17 @@ func (t andTerm) String() string {
return strings.Join(terms, ",")
}
-func try(queryPiece, op string) (lhs, rhs string, ok bool) {
- pieces := strings.Split(queryPiece, op)
+func try(selectorPiece, op string) (lhs, rhs string, ok bool) {
+ pieces := strings.Split(selectorPiece, op)
if len(pieces) == 2 {
return pieces[0], pieces[1], true
}
return "", "", false
}
-// Given a Set, return a Query which will match exactly that Set.
-func QueryFromSet(ls Set) Query {
- var items []Query
+// Given a Set, return a Selector which will match exactly that Set.
+func SelectorFromSet(ls Set) Selector {
+ var items []Selector
for label, value := range ls {
items = append(items, &hasTerm{label: label, value: value})
}
@@ -98,10 +98,10 @@ func QueryFromSet(ls Set) Query {
return andTerm(items)
}
-// Takes a string repsenting a label query and returns an object suitable for matching, or an error.
-func ParseQuery(query string) (Query, error) {
- parts := strings.Split(query, ",")
- var items []Query
+// Takes a string repsenting a selector and returns an object suitable for matching, or an error.
+func ParseSelector(selector string) (Selector, error) {
+ parts := strings.Split(selector, ",")
+ var items []Selector
for _, part := range parts {
if part == "" {
continue
@@ -113,7 +113,7 @@ func ParseQuery(query string) (Query, error) {
} else if lhs, rhs, ok := try(part, "="); ok {
items = append(items, &hasTerm{label: lhs, value: rhs})
} else {
- return nil, fmt.Errorf("invalid label query: '%s'; can't understand '%s'", query, part)
+ return nil, fmt.Errorf("invalid selector: '%s'; can't understand '%s'", selector, part)
}
}
if len(items) == 1 {
diff --git a/pkg/labels/query_test.go b/pkg/labels/query_test.go
index 38dae8b489..2947e042bf 100644
--- a/pkg/labels/query_test.go
+++ b/pkg/labels/query_test.go
@@ -20,7 +20,7 @@ import (
"testing"
)
-func TestQueryParse(t *testing.T) {
+func TestSelectorParse(t *testing.T) {
testGoodStrings := []string{
"x=a,y=b,z=c",
"",
@@ -31,7 +31,7 @@ func TestQueryParse(t *testing.T) {
"x==a==b",
}
for _, test := range testGoodStrings {
- lq, err := ParseQuery(test)
+ lq, err := ParseSelector(test)
if err != nil {
t.Errorf("%v: error %v (%#v)\n", test, err, err)
}
@@ -40,42 +40,42 @@ func TestQueryParse(t *testing.T) {
}
}
for _, test := range testBadStrings {
- _, err := ParseQuery(test)
+ _, err := ParseSelector(test)
if err == nil {
t.Errorf("%v: did not get expected error\n", test)
}
}
}
-func expectMatch(t *testing.T, query string, ls Set) {
- lq, err := ParseQuery(query)
+func expectMatch(t *testing.T, selector string, ls Set) {
+ lq, err := ParseSelector(selector)
if err != nil {
- t.Errorf("Unable to parse %v as a query\n", query)
+ t.Errorf("Unable to parse %v as a selector\n", selector)
return
}
if !lq.Matches(ls) {
- t.Errorf("Wanted %s to match '%s', but it did not.\n", query, ls)
+ t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
}
}
-func expectNoMatch(t *testing.T, query string, ls Set) {
- lq, err := ParseQuery(query)
+func expectNoMatch(t *testing.T, selector string, ls Set) {
+ lq, err := ParseSelector(selector)
if err != nil {
- t.Errorf("Unable to parse %v as a query\n", query)
+ t.Errorf("Unable to parse %v as a selector\n", selector)
return
}
if lq.Matches(ls) {
- t.Errorf("Wanted '%s' to not match '%s', but it did.", query, ls)
+ t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
}
}
func TestEverything(t *testing.T) {
if !Everything().Matches(Set{"x": "y"}) {
- t.Errorf("Nil query didn't match")
+ t.Errorf("Nil selector didn't match")
}
}
-func TestLabelQueryMatches(t *testing.T) {
+func TestSelectorMatches(t *testing.T) {
expectMatch(t, "", Set{"x": "y"})
expectMatch(t, "x=y", Set{"x": "y"})
expectMatch(t, "x=y,z=w", Set{"x": "y", "z": "w"})
@@ -96,15 +96,15 @@ func TestLabelQueryMatches(t *testing.T) {
expectNoMatch(t, "foo=bar,foobar=bar,baz=blah", labelset)
}
-func expectMatchDirect(t *testing.T, query, ls Set) {
- if !QueryFromSet(query).Matches(ls) {
- t.Errorf("Wanted %s to match '%s', but it did not.\n", query, ls)
+func expectMatchDirect(t *testing.T, selector, ls Set) {
+ if !SelectorFromSet(selector).Matches(ls) {
+ t.Errorf("Wanted %s to match '%s', but it did not.\n", selector, ls)
}
}
-func expectNoMatchDirect(t *testing.T, query, ls Set) {
- if QueryFromSet(query).Matches(ls) {
- t.Errorf("Wanted '%s' to not match '%s', but it did.", query, ls)
+func expectNoMatchDirect(t *testing.T, selector, ls Set) {
+ if SelectorFromSet(selector).Matches(ls) {
+ t.Errorf("Wanted '%s' to not match '%s', but it did.", selector, ls)
}
}
diff --git a/pkg/registry/controller_registry.go b/pkg/registry/controller_registry.go
index 1824ba965a..1b6aabab84 100644
--- a/pkg/registry/controller_registry.go
+++ b/pkg/registry/controller_registry.go
@@ -35,12 +35,12 @@ func MakeControllerRegistryStorage(registry ControllerRegistry) apiserver.RESTSt
}
}
-func (storage *ControllerRegistryStorage) List(query labels.Query) (interface{}, error) {
+func (storage *ControllerRegistryStorage) List(selector labels.Selector) (interface{}, error) {
result := api.ReplicationControllerList{JSONBase: api.JSONBase{Kind: "cluster#replicationControllerList"}}
controllers, err := storage.registry.ListControllers()
if err == nil {
for _, controller := range controllers {
- if query.Matches(labels.Set(controller.Labels)) {
+ if selector.Matches(labels.Set(controller.Labels)) {
result.Items = append(result.Items, controller)
}
}
diff --git a/pkg/registry/controller_registry_test.go b/pkg/registry/controller_registry_test.go
index 14eac7e498..8d2257ec0d 100644
--- a/pkg/registry/controller_registry_test.go
+++ b/pkg/registry/controller_registry_test.go
@@ -139,7 +139,7 @@ func TestControllerParsing(t *testing.T) {
},
DesiredState: api.ReplicationControllerState{
Replicas: 2,
- ReplicasInSet: map[string]string{
+ ReplicaSelector: map[string]string{
"name": "nginx",
},
PodTemplate: api.PodTemplate{
diff --git a/pkg/registry/endpoints.go b/pkg/registry/endpoints.go
index 5601db2f13..f29417a1e6 100644
--- a/pkg/registry/endpoints.go
+++ b/pkg/registry/endpoints.go
@@ -13,6 +13,7 @@ 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 registry
import (
@@ -42,7 +43,7 @@ func (e *EndpointController) SyncServiceEndpoints() error {
}
var resultErr error
for _, service := range services.Items {
- pods, err := e.podRegistry.ListPods(labels.QueryFromSet(labels.Set(service.Labels)))
+ pods, err := e.podRegistry.ListPods(labels.Set(service.Selector).AsSelector())
if err != nil {
log.Printf("Error syncing service: %#v, skipping.", service)
resultErr = err
diff --git a/pkg/registry/endpoints_test.go b/pkg/registry/endpoints_test.go
index af34ff23b7..65bab95968 100644
--- a/pkg/registry/endpoints_test.go
+++ b/pkg/registry/endpoints_test.go
@@ -49,7 +49,7 @@ func TestSyncEndpointsItems(t *testing.T) {
list: api.ServiceList{
Items: []api.Service{
{
- Labels: map[string]string{
+ Selector: map[string]string{
"foo": "bar",
},
},
@@ -92,7 +92,7 @@ func TestSyncEndpointsPodError(t *testing.T) {
list: api.ServiceList{
Items: []api.Service{
{
- Labels: map[string]string{
+ Selector: map[string]string{
"foo": "bar",
},
},
diff --git a/pkg/registry/etcd_registry.go b/pkg/registry/etcd_registry.go
index 389e4b98ec..a4df170c15 100644
--- a/pkg/registry/etcd_registry.go
+++ b/pkg/registry/etcd_registry.go
@@ -59,7 +59,7 @@ func (registry *EtcdRegistry) helper() *util.EtcdHelper {
return &util.EtcdHelper{registry.etcdClient}
}
-func (registry *EtcdRegistry) ListPods(query labels.Query) ([]api.Pod, error) {
+func (registry *EtcdRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
pods := []api.Pod{}
for _, machine := range registry.machines {
var machinePods []api.Pod
@@ -68,7 +68,7 @@ func (registry *EtcdRegistry) ListPods(query labels.Query) ([]api.Pod, error) {
return pods, err
}
for _, pod := range machinePods {
- if query.Matches(labels.Set(pod.Labels)) {
+ if selector.Matches(labels.Set(pod.Labels)) {
pod.CurrentState.Host = machine
pods = append(pods, pod)
}
diff --git a/pkg/registry/etcd_registry_test.go b/pkg/registry/etcd_registry_test.go
index 85676d80f8..407de8d7e3 100644
--- a/pkg/registry/etcd_registry_test.go
+++ b/pkg/registry/etcd_registry_test.go
@@ -604,16 +604,21 @@ func TestEtcdUpdateService(t *testing.T) {
fakeClient := util.MakeFakeEtcdClient(t)
fakeClient.Set("/registry/services/specs/foo", util.MakeJSONString(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"})
- err := registry.UpdateService(api.Service{
+ testService := api.Service{
JSONBase: api.JSONBase{ID: "foo"},
Labels: map[string]string{
"baz": "bar",
},
- })
+ Selector: map[string]string{
+ "baz": "bar",
+ },
+ }
+ err := registry.UpdateService(testService)
expectNoError(t, err)
svc, err := registry.GetService("foo")
- if svc.Labels["baz"] != "bar" {
- t.Errorf("Unexpected service: %#v", svc)
+ expectNoError(t, err)
+ if !reflect.DeepEqual(*svc, testService) {
+ t.Errorf("Unexpected service: got %#v, wanted %#v", svc, testService)
}
}
diff --git a/pkg/registry/interfaces.go b/pkg/registry/interfaces.go
index bf0e2728e9..de077447ff 100644
--- a/pkg/registry/interfaces.go
+++ b/pkg/registry/interfaces.go
@@ -22,8 +22,8 @@ import (
// PodRegistry is an interface implemented by things that know how to store Pod objects.
type PodRegistry interface {
- // ListPods obtains a list of pods that match query.
- ListPods(query labels.Query) ([]api.Pod, error)
+ // ListPods obtains a list of pods that match selector.
+ ListPods(selector labels.Selector) ([]api.Pod, error)
// Get a specific pod
GetPod(podID string) (*api.Pod, error)
// Create a pod based on a specification, schedule it onto a specific machine.
diff --git a/pkg/registry/memory_registry.go b/pkg/registry/memory_registry.go
index a217552591..994649df93 100644
--- a/pkg/registry/memory_registry.go
+++ b/pkg/registry/memory_registry.go
@@ -36,10 +36,10 @@ func MakeMemoryRegistry() *MemoryRegistry {
}
}
-func (registry *MemoryRegistry) ListPods(query labels.Query) ([]api.Pod, error) {
+func (registry *MemoryRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
result := []api.Pod{}
for _, value := range registry.podData {
- if query.Matches(labels.Set(value.Labels)) {
+ if selector.Matches(labels.Set(value.Labels)) {
result = append(result, value)
}
}
diff --git a/pkg/registry/mock_registry.go b/pkg/registry/mock_registry.go
index b2e1bff59b..7a3db516cb 100644
--- a/pkg/registry/mock_registry.go
+++ b/pkg/registry/mock_registry.go
@@ -33,13 +33,13 @@ func MakeMockPodRegistry(pods []api.Pod) *MockPodRegistry {
}
}
-func (registry *MockPodRegistry) ListPods(query labels.Query) ([]api.Pod, error) {
+func (registry *MockPodRegistry) ListPods(selector labels.Selector) ([]api.Pod, error) {
if registry.err != nil {
return registry.pods, registry.err
}
var filtered []api.Pod
for _, pod := range registry.pods {
- if query.Matches(labels.Set(pod.Labels)) {
+ if selector.Matches(labels.Set(pod.Labels)) {
filtered = append(filtered, pod)
}
}
diff --git a/pkg/registry/pod_registry.go b/pkg/registry/pod_registry.go
index c81ba7b563..a1698176ab 100644
--- a/pkg/registry/pod_registry.go
+++ b/pkg/registry/pod_registry.go
@@ -54,9 +54,9 @@ func MakePodRegistryStorage(registry PodRegistry, containerInfo client.Container
}
}
-func (storage *PodRegistryStorage) List(query labels.Query) (interface{}, error) {
+func (storage *PodRegistryStorage) List(selector labels.Selector) (interface{}, error) {
var result api.PodList
- pods, err := storage.registry.ListPods(query)
+ pods, err := storage.registry.ListPods(selector)
if err == nil {
result.Items = pods
// Get cached info for the list currently.
diff --git a/pkg/registry/service_registry.go b/pkg/registry/service_registry.go
index 128e3b571b..c30029bd71 100644
--- a/pkg/registry/service_registry.go
+++ b/pkg/registry/service_registry.go
@@ -59,7 +59,7 @@ func GetServiceEnvironmentVariables(registry ServiceRegistry, machine string) ([
return result, nil
}
-func (sr *ServiceRegistryStorage) List(query labels.Query) (interface{}, error) {
+func (sr *ServiceRegistryStorage) List(selector labels.Selector) (interface{}, error) {
list, err := sr.registry.ListServices()
if err != nil {
return nil, err
@@ -67,7 +67,7 @@ func (sr *ServiceRegistryStorage) List(query labels.Query) (interface{}, error)
list.Kind = "cluster#serviceList"
var filtered []api.Service
for _, service := range list.Items {
- if query.Matches(labels.Set(service.Labels)) {
+ if selector.Matches(labels.Set(service.Labels)) {
filtered = append(filtered, service)
}
}