diff --git a/pkg/api/types.go b/pkg/api/types.go index 0c7ea04a756..9fd31f70369 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -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/cloudcfg/cloudcfg.go b/pkg/cloudcfg/cloudcfg.go index c1ec9f35cf8..feb53f284b0 100644 --- a/pkg/cloudcfg/cloudcfg.go +++ b/pkg/cloudcfg/cloudcfg.go @@ -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/parse_test.go b/pkg/cloudcfg/parse_test.go index 1884466de6e..f8ac85b89de 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 74ea104bfec..d72bfd384ea 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" ) @@ -62,7 +63,7 @@ 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 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.ReplicasInSet), 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/labels/labels.go b/pkg/labels/labels.go index 156e18561c3..35a800126c8 100644 --- a/pkg/labels/labels.go +++ b/pkg/labels/labels.go @@ -45,3 +45,8 @@ func (ls Set) String() string { func (ls Set) Get(label string) string { return ls[label] } + +// Convenience function: convert these labels to a query. +func (ls Set) AsQuery() Query { + return QueryFromSet(ls) +} diff --git a/pkg/registry/endpoints.go b/pkg/registry/endpoints.go index 5601db2f136..37257c9117e 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).AsQuery()) 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 af34ff23b7d..65bab959682 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_test.go b/pkg/registry/etcd_registry_test.go index 85676d80f88..407de8d7e3b 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) } }