Change:
It doesn't make sense to define pod template with a set of labels that is strict subset of replicaSelector (or at least I can't find an use-case). For that reason I think that the labels in pod template part of replication controller should be optional and user should care about them only if he wants to define a superset of what replicaSelector already defines.
I've heard the same comments from a client. I think that it'd be more intuitive if we always specify pod labels in the template (so that we can copy&paste pod definition), and replicaSelector is optional (by default pod labels).
It would be reasonable for the selector to be a subset. I'm fine with intelligent defaulting but we need to be careful not to conflate the 2 concepts, which I think would increase the amount of confusion.
Setting RC selector from pod template labels SGTM. Any concerns It wouldn't have to work with separate templates, though it would be desirable if it did. It would be nice if we could add preconditions based on other objects (resource version of pod template in this case) to etcd transactions.
I think we agreed in another issue that defaulting the selector from the pod template labels is reasonable. No argument from me. One problem with pod templates is that we lose the strict relationship between selector and template, so if you change the template the RC needs to behave intelligently (I refuse to create more pods because the template selector doesn't match mine, etc)
We should do this, and we should default replicas to 1. We could also consider defaulting replication controller labels from pod template labels. That way, essentially the only thing that would need to be specified for a singleton RC would be the pod template.
I don't think we can default replicas to 1, since we can't tell the difference between an explicit zero and a default zero, and I think there are lots of reasonable cases where you want to set replicas == 0 on create. (esp. in the context of socket activation)
Responded on the PR: We can distinguish default from 0 if we make it a pointer.

Discussion:
func init() { api.Scheme.AddDefaultingFuncs( <ins> func(obj *ReplicationController) { if len(obj.DesiredState.ReplicaSelector) == 0 { obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels } if len(obj.Labels) == 0 { obj.Labels = obj.DesiredState.PodTemplate.Labels } }, </ins> func(obj *Volume) { if util.AllPtrFieldsNil(&obj.Source) { obj.Source = VolumeSource{

func init() { api.Scheme.AddDefaultingFuncs( <ins> func(obj *ReplicationController) { if len(obj.DesiredState.ReplicaSelector) == 0 { obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels } if len(obj.Labels) == 0 { obj.Labels = obj.DesiredState.PodTemplate.Labels } }, </ins> func(obj *Volume) { if util.AllPtrFieldsNil(&obj.Source) { glog.Errorf("Defaulting volume source for %v", obj)

return obj3 } <ins> func TestSetDefaultReplicationController(t *testing.T) { tests := []struct { rc             *current.ReplicationController expectLabels   bool expectSelector bool }{ { rc: &current.ReplicationController{ DesiredState: current.ReplicationControllerState{ PodTemplate: current.PodTemplate{ Labels: map[string]string{ "foo": "bar", }, }, }, }, expectLabels:   true, expectSelector: true, }, { rc: &current.ReplicationController{ Labels: map[string]string{ "bar": "foo", }, DesiredState: current.ReplicationControllerState{ PodTemplate: current.PodTemplate{ Labels: map[string]string{ "foo": "bar", }, }, }, }, expectLabels:   false, expectSelector: true, }, { rc: &current.ReplicationController{ Labels: map[string]string{ "bar": "foo", }, DesiredState: current.ReplicationControllerState{ ReplicaSelector: map[string]string{ "some": "other", }, PodTemplate: current.PodTemplate{ Labels: map[string]string{ "foo": "bar", }, }, }, }, expectLabels:   false, expectSelector: false, }, { rc: &current.ReplicationController{ DesiredState: current.ReplicationControllerState{ ReplicaSelector: map[string]string{ "some": "other", }, PodTemplate: current.PodTemplate{ Labels: map[string]string{ "foo": "bar", }, }, }, }, expectLabels:   true, expectSelector: false, }, } for _, test := range tests { rc := test.rc obj2 := roundTrip(t, runtime.Object(rc)) rc2, ok := obj2.(*current.ReplicationController) if !ok { t.Errorf("unexpected object: %v", rc2) t.FailNow() } if test.expectSelector != reflect.DeepEqual(rc2.DesiredState.ReplicaSelector, rc2.DesiredState.PodTemplate.Labels) { if test.expectSelector { t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.DesiredState.ReplicaSelector) } else { t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels) } } if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.DesiredState.PodTemplate.Labels) { if test.expectLabels { t.Errorf("expected: %v, got: %v", rc2.DesiredState.PodTemplate.Labels, rc2.Labels) } else { t.Errorf("unexpected equality: %v", rc2.DesiredState.PodTemplate.Labels) } } } } </ins> func TestSetDefaultService(t *testing.T) { svc := &current.Service{} obj2 := roundTrip(t, runtime.Object(svc))

func init() { api.Scheme.AddDefaultingFuncs( <ins> func(obj *ReplicationController) { var labels map[string]string if obj.Spec.Template != nil { labels = obj.Spec.Template.Labels } // TODO: support templates defined elsewhere when we support them in the API if labels != nil { if len(obj.Spec.Selector) == 0 { obj.Spec.Selector = labels } if len(obj.Labels) == 0 { obj.Labels = labels } } }, </ins> func(obj *Volume) { if util.AllPtrFieldsNil(&obj.VolumeSource) { obj.VolumeSource = VolumeSource{

return obj3 } <ins> func TestSetDefaultReplicationController(t *testing.T) { tests := []struct { rc             *current.ReplicationController expectLabels   bool expectSelector bool }{ { rc: &current.ReplicationController{ Spec: current.ReplicationControllerSpec{ Template: &current.PodTemplateSpec{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, }, }, }, expectLabels:   true, expectSelector: true, }, { rc: &current.ReplicationController{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "bar": "foo", }, }, Spec: current.ReplicationControllerSpec{ Template: &current.PodTemplateSpec{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, }, }, }, expectLabels:   false, expectSelector: true, }, { rc: &current.ReplicationController{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "bar": "foo", }, }, Spec: current.ReplicationControllerSpec{ Selector: map[string]string{ "some": "other", }, Template: &current.PodTemplateSpec{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, }, }, }, expectLabels:   false, expectSelector: false, }, { rc: &current.ReplicationController{ Spec: current.ReplicationControllerSpec{ Selector: map[string]string{ "some": "other", }, Template: &current.PodTemplateSpec{ ObjectMeta: current.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, }, }, }, expectLabels:   true, expectSelector: false, }, } for _, test := range tests { rc := test.rc obj2 := roundTrip(t, runtime.Object(rc)) rc2, ok := obj2.(*current.ReplicationController) if !ok { t.Errorf("unexpected object: %v", rc2) t.FailNow() } if test.expectSelector != reflect.DeepEqual(rc2.Spec.Selector, rc2.Spec.Template.Labels) { if test.expectSelector { t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Spec.Selector) } else { t.Errorf("unexpected equality: %v", rc.Spec.Selector) } } if test.expectLabels != reflect.DeepEqual(rc2.Labels, rc2.Spec.Template.Labels) { if test.expectLabels { t.Errorf("expected: %v, got: %v", rc2.Spec.Template.Labels, rc2.Labels) } else { t.Errorf("unexpected equality: %v", rc.Labels) } } } } </ins> func TestSetDefaultService(t *testing.T) { svc := &current.Service{} obj2 := roundTrip(t, runtime.Object(svc))

Replicas int `json:"replicas" description:"number of replicas desired"` // Selector is a label query over pods that should match the Replicas count. <del> Selector map[string]string `json:"selector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller"` </del> <ins> // If Selector is empty, it is defaulted to the labels present on the Pod template. Selector map[string]string `json:"selector,omitempty" description:"label keys and values that must match in order to be controlled by this replication controller, if empty defaulted to labels on Pod template"` </ins> // TemplateRef is a reference to an object that describes the pod that will be created if // insufficient replicas are detected.

// ReplicationController represents the configuration of a replication controller. type ReplicationController struct { <del> TypeMeta   `json:",inline"` </del> <ins> TypeMeta `json:",inline"` // If the Labels of a ReplicationController are empty, they are defaulted to be the same as the Pod(s) that the replication controller manages. </ins> ObjectMeta `json:"metadata,omitempty" description:"standard object metadata; see https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/api-conventions.md#metadata"` // Spec defines the desired behavior of this replication controller.

// Status.Replicas should go up from 2->4 even though we created 5-4=1 pod rc.Status = api.ReplicationControllerStatus{Replicas: 4} <ins> // These are set by default. rc.Spec.Selector = rc.Spec.Template.Labels rc.Labels = rc.Spec.Template.Labels </ins> decRc := runtime.EncodeOrDie(testapi.Codec(), &rc) fakeUpdateHandler.ValidateRequest(t, testapi.ResourcePathWithQueryParams(replicationControllerResourceName(), rc.Namespace, rc.Name), "PUT", &decRc) validateSyncReplication(t, &fakePodControl, 1, 0)

storage, _ := newStorage(t) emptyName := validController emptyName.Name = "" <del> emptySelector := validController emptySelector.Spec.Selector = map[string]string{} failureCases := []api.ReplicationController{emptyName, emptySelector} </del> <ins> failureCases := []api.ReplicationController{emptyName} </ins> for _, failureCase := range failureCases { c, err := storage.Create(ctx, &failureCase) if c != nil {