Separate labels and selector in services for clarity

This commit is contained in:
Daniel Smith 2014-06-18 16:01:49 -07:00
parent 59c08db4c1
commit c4649d539b
8 changed files with 39 additions and 23 deletions

View File

@ -138,11 +138,17 @@ type ServiceList struct {
} }
// Defines a service abstraction by a name (for example, mysql) consisting of local port // 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 { type Service struct {
JSONBase `json:",inline" yaml:",inline"` JSONBase `json:",inline" yaml:",inline"`
Port int `json:"port,omitempty" yaml:"port,omitempty"` Port int `json:"port,omitempty" yaml:"port,omitempty"`
// This service's labels.
Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` 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"` CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
} }

View File

@ -255,6 +255,9 @@ func createService(name string, port int, client client.ClientInterface) (api.Se
Labels: map[string]string{ Labels: map[string]string{
"name": name, "name": name,
}, },
Selector: map[string]string{
"name": name,
},
} }
svc, err := client.CreateService(svc) svc, err := client.CreateService(svc)
return svc, err return svc, err

View File

@ -63,6 +63,9 @@ func TestParseService(t *testing.T) {
Labels: map[string]string{ Labels: map[string]string{
"area": "staging", "area": "staging",
}, },
Selector: map[string]string{
"area": "staging",
},
}) })
} }

View File

@ -24,6 +24,7 @@ import (
"text/tabwriter" "text/tabwriter"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
"gopkg.in/v1/yaml" "gopkg.in/v1/yaml"
) )
@ -62,7 +63,7 @@ type HumanReadablePrinter struct{}
var podColumns = []string{"Name", "Image(s)", "Host", "Labels"} var podColumns = []string{"Name", "Image(s)", "Host", "Labels"}
var replicationControllerColumns = []string{"Name", "Image(s)", "Label Query", "Replicas"} 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 { func (h *HumanReadablePrinter) unknown(data string, w io.Writer) error {
_, err := fmt.Fprintf(w, "Unknown object: %s", data) _, err := fmt.Fprintf(w, "Unknown object: %s", data)
@ -89,17 +90,9 @@ func (h *HumanReadablePrinter) makeImageList(manifest api.ContainerManifest) str
return strings.Join(images, ",") 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 { func (h *HumanReadablePrinter) printPod(pod api.Pod, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", _, 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 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 { func (h *HumanReadablePrinter) printReplicationController(ctrl api.ReplicationController, w io.Writer) error {
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%d\n", _, 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 return err
} }
@ -128,7 +121,7 @@ func (h *HumanReadablePrinter) printReplicationControllerList(list api.Replicati
} }
func (h *HumanReadablePrinter) printService(svc api.Service, w io.Writer) error { 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 return err
} }

View File

@ -45,3 +45,8 @@ func (ls Set) String() string {
func (ls Set) Get(label string) string { func (ls Set) Get(label string) string {
return ls[label] return ls[label]
} }
// Convenience function: convert these labels to a query.
func (ls Set) AsQuery() Query {
return QueryFromSet(ls)
}

View File

@ -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 See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
package registry package registry
import ( import (
@ -42,7 +43,7 @@ func (e *EndpointController) SyncServiceEndpoints() error {
} }
var resultErr error var resultErr error
for _, service := range services.Items { 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 { if err != nil {
log.Printf("Error syncing service: %#v, skipping.", service) log.Printf("Error syncing service: %#v, skipping.", service)
resultErr = err resultErr = err

View File

@ -49,7 +49,7 @@ func TestSyncEndpointsItems(t *testing.T) {
list: api.ServiceList{ list: api.ServiceList{
Items: []api.Service{ Items: []api.Service{
{ {
Labels: map[string]string{ Selector: map[string]string{
"foo": "bar", "foo": "bar",
}, },
}, },
@ -92,7 +92,7 @@ func TestSyncEndpointsPodError(t *testing.T) {
list: api.ServiceList{ list: api.ServiceList{
Items: []api.Service{ Items: []api.Service{
{ {
Labels: map[string]string{ Selector: map[string]string{
"foo": "bar", "foo": "bar",
}, },
}, },

View File

@ -604,16 +604,21 @@ func TestEtcdUpdateService(t *testing.T) {
fakeClient := util.MakeFakeEtcdClient(t) fakeClient := util.MakeFakeEtcdClient(t)
fakeClient.Set("/registry/services/specs/foo", util.MakeJSONString(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0) fakeClient.Set("/registry/services/specs/foo", util.MakeJSONString(api.Service{JSONBase: api.JSONBase{ID: "foo"}}), 0)
registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"}) registry := MakeTestEtcdRegistry(fakeClient, []string{"machine"})
err := registry.UpdateService(api.Service{ testService := api.Service{
JSONBase: api.JSONBase{ID: "foo"}, JSONBase: api.JSONBase{ID: "foo"},
Labels: map[string]string{ Labels: map[string]string{
"baz": "bar", "baz": "bar",
}, },
}) Selector: map[string]string{
"baz": "bar",
},
}
err := registry.UpdateService(testService)
expectNoError(t, err) expectNoError(t, err)
svc, err := registry.GetService("foo") svc, err := registry.GetService("foo")
if svc.Labels["baz"] != "bar" { expectNoError(t, err)
t.Errorf("Unexpected service: %#v", svc) if !reflect.DeepEqual(*svc, testService) {
t.Errorf("Unexpected service: got %#v, wanted %#v", svc, testService)
} }
} }