diff --git a/pkg/apis/extensions/types.go b/pkg/apis/extensions/types.go index 967c0a7e98..82bae73f2e 100644 --- a/pkg/apis/extensions/types.go +++ b/pkg/apis/extensions/types.go @@ -298,7 +298,7 @@ type DaemonSetSpec struct { // Must match in order to be controlled. // If empty, defaulted to labels on Pod template. // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors - Selector map[string]string `json:"selector,omitempty"` + Selector *PodSelector `json:"selector,omitempty"` // Template is the object that describes the pod that will be created. // The DaemonSet will create exactly one copy of this pod on every node diff --git a/pkg/apis/extensions/v1beta1/defaults.go b/pkg/apis/extensions/v1beta1/defaults.go index c30858975d..d9bad2ca6d 100644 --- a/pkg/apis/extensions/v1beta1/defaults.go +++ b/pkg/apis/extensions/v1beta1/defaults.go @@ -35,8 +35,10 @@ func addDefaultingFuncs() { } // 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 obj.Spec.Selector == nil { + obj.Spec.Selector = &PodSelector{ + MatchLabels: labels, + } } if len(obj.Labels) == 0 { obj.Labels = labels diff --git a/pkg/apis/extensions/v1beta1/types.go b/pkg/apis/extensions/v1beta1/types.go index 37322f25ff..fbdc6c5069 100644 --- a/pkg/apis/extensions/v1beta1/types.go +++ b/pkg/apis/extensions/v1beta1/types.go @@ -296,7 +296,7 @@ type DaemonSetSpec struct { // Must match in order to be controlled. // If empty, defaulted to labels on Pod template. // More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors - Selector map[string]string `json:"selector,omitempty"` + Selector *PodSelector `json:"selector,omitempty"` // Template is the object that describes the pod that will be created. // The DaemonSet will create exactly one copy of this pod on every node diff --git a/pkg/apis/extensions/validation/validation.go b/pkg/apis/extensions/validation/validation.go index 5a256398e1..92caa9fa6f 100644 --- a/pkg/apis/extensions/validation/validation.go +++ b/pkg/apis/extensions/validation/validation.go @@ -185,26 +185,26 @@ func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplat func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec) errs.ValidationErrorList { allErrs := errs.ValidationErrorList{} - selector := labels.Set(spec.Selector).AsSelector() - if selector.Empty() { - allErrs = append(allErrs, errs.NewFieldRequired("selector")) - } + allErrs = append(allErrs, ValidatePodSelector(spec.Selector)...) if spec.Template == nil { allErrs = append(allErrs, errs.NewFieldRequired("template")) - } else { - labels := labels.Set(spec.Template.Labels) - if !selector.Matches(labels) { - allErrs = append(allErrs, errs.NewFieldInvalid("template.metadata.labels", spec.Template.Labels, "selector does not match template")) - } - allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template).Prefix("template")...) - // Daemons typically run on more than one node, so mark Read-Write persistent disks as invalid. - allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes).Prefix("template.spec.volumes")...) - // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). - if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { - allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) - } + return allErrs } + + selector, err := extensions.PodSelectorAsSelector(spec.Selector) + if err == nil && !selector.Matches(labels.Set(spec.Template.Labels)) { + allErrs = append(allErrs, errs.NewFieldInvalid("template.metadata.labels", spec.Template.Labels, "selector does not match template")) + } + + allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template).Prefix("template")...) + // Daemons typically run on more than one node, so mark Read-Write persistent disks as invalid. + allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes).Prefix("template.spec.volumes")...) + // RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec(). + if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { + allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) + } + return allErrs } @@ -226,7 +226,6 @@ func ValidatePositiveIntOrPercent(intOrPercent util.IntOrString, fieldName strin if !validation.IsValidPercent(intOrPercent.StrVal) { allErrs = append(allErrs, errs.NewFieldInvalid(fieldName, intOrPercent, "value should be int(5) or percentage(5%)")) } - } else if intOrPercent.Kind == util.IntstrInt { allErrs = append(allErrs, apivalidation.ValidatePositiveField(int64(intOrPercent.IntVal), fieldName)...) } diff --git a/pkg/apis/extensions/validation/validation_test.go b/pkg/apis/extensions/validation/validation_test.go index 117bd900f7..bd8630c686 100644 --- a/pkg/apis/extensions/validation/validation_test.go +++ b/pkg/apis/extensions/validation/validation_test.go @@ -369,14 +369,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, @@ -385,14 +385,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector2, + Selector: &extensions.PodSelector{MatchLabels: validSelector2}, Template: &validPodTemplateAbc2.Template, }, }, @@ -401,14 +401,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateNodeSelector.Template, }, }, @@ -426,14 +426,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, @@ -442,14 +442,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: invalidSelector, + Selector: &extensions.PodSelector{MatchLabels: invalidSelector}, Template: &validPodTemplateAbc.Template, }, }, @@ -458,14 +458,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &invalidPodTemplate.Template, }, }, @@ -474,14 +474,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateDef.Template, }, }, @@ -490,14 +490,14 @@ func TestValidateDaemonSetUpdate(t *testing.T) { old: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplateAbc.Template, }, }, update: extensions.DaemonSet{ ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &readWriteVolumePodTemplate.Template, }, }, @@ -540,14 +540,14 @@ func TestValidateDaemonSet(t *testing.T) { { ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, { ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, @@ -562,14 +562,14 @@ func TestValidateDaemonSet(t *testing.T) { "zero-length ID": { ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, "missing-namespace": { ObjectMeta: api.ObjectMeta{Name: "abc-123"}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, @@ -582,14 +582,14 @@ func TestValidateDaemonSet(t *testing.T) { "selector_doesnt_match": { ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{"foo": "bar"}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{"foo": "bar"}}, Template: &validPodTemplate.Template, }, }, "invalid manifest": { ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault}, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, }, }, "invalid_label": { @@ -601,7 +601,7 @@ func TestValidateDaemonSet(t *testing.T) { }, }, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, @@ -626,7 +626,7 @@ func TestValidateDaemonSet(t *testing.T) { }, }, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &validPodTemplate.Template, }, }, @@ -636,7 +636,7 @@ func TestValidateDaemonSet(t *testing.T) { Namespace: api.NamespaceDefault, }, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &api.PodTemplateSpec{ Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyOnFailure, @@ -655,7 +655,7 @@ func TestValidateDaemonSet(t *testing.T) { Namespace: api.NamespaceDefault, }, Spec: extensions.DaemonSetSpec{ - Selector: validSelector, + Selector: &extensions.PodSelector{MatchLabels: validSelector}, Template: &api.PodTemplateSpec{ Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyNever, diff --git a/pkg/client/cache/listers.go b/pkg/client/cache/listers.go index 34946fc127..5425f857cb 100644 --- a/pkg/client/cache/listers.go +++ b/pkg/client/cache/listers.go @@ -247,7 +247,11 @@ func (s *StoreToDaemonSetLister) GetPodDaemonSets(pod *api.Pod) (daemonSets []ex if daemonSet.Namespace != pod.Namespace { continue } - selector = labels.Set(daemonSet.Spec.Selector).AsSelector() + selector, err = extensions.PodSelectorAsSelector(daemonSet.Spec.Selector) + if err != nil { + // this should not happen if the DaemonSet passed validation + return nil, err + } // If a daemonSet with a nil or empty selector creeps in, it should match nothing, not everything. if selector.Empty() || !selector.Matches(labels.Set(pod.Labels)) { diff --git a/pkg/client/cache/listers_test.go b/pkg/client/cache/listers_test.go index 4910c6da3e..f108c697e2 100644 --- a/pkg/client/cache/listers_test.go +++ b/pkg/client/cache/listers_test.go @@ -272,7 +272,7 @@ func TestStoreToDaemonSetLister(t *testing.T) { { ObjectMeta: api.ObjectMeta{Name: "basic", Namespace: "ns"}, Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{"foo": "baz"}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{"foo": "baz"}}, }, }, }, @@ -311,13 +311,13 @@ func TestStoreToDaemonSetLister(t *testing.T) { { ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{"foo": "bar"}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{"foo": "bar"}}, }, }, { ObjectMeta: api.ObjectMeta{Name: "bar", Namespace: "ns"}, Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{"foo": "bar"}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{"foo": "bar"}}, }, }, }, diff --git a/pkg/controller/daemon/controller.go b/pkg/controller/daemon/controller.go index c24faefc14..18a4e32add 100644 --- a/pkg/controller/daemon/controller.go +++ b/pkg/controller/daemon/controller.go @@ -323,7 +323,11 @@ func (dsc *DaemonSetsController) updateNode(old, cur interface{}) { // getNodesToDaemonSetPods returns a map from nodes to daemon pods (corresponding to ds) running on the nodes. func (dsc *DaemonSetsController) getNodesToDaemonPods(ds *extensions.DaemonSet) (map[string][]*api.Pod, error) { nodeToDaemonPods := make(map[string][]*api.Pod) - daemonPods, err := dsc.podStore.Pods(ds.Namespace).List(labels.Set(ds.Spec.Selector).AsSelector()) + selector, err := extensions.PodSelectorAsSelector(ds.Spec.Selector) + if err != nil { + return nil, err + } + daemonPods, err := dsc.podStore.Pods(ds.Namespace).List(selector) if err != nil { return nodeToDaemonPods, err } diff --git a/pkg/controller/daemon/controller_test.go b/pkg/controller/daemon/controller_test.go index 5b4f68e8c0..bd91bd2b2f 100644 --- a/pkg/controller/daemon/controller_test.go +++ b/pkg/controller/daemon/controller_test.go @@ -55,7 +55,7 @@ func newDaemonSet(name string) *extensions.DaemonSet { Namespace: api.NamespaceDefault, }, Spec: extensions.DaemonSetSpec{ - Selector: simpleDaemonSetLabel, + Selector: &extensions.PodSelector{MatchLabels: simpleDaemonSetLabel}, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: simpleDaemonSetLabel, diff --git a/pkg/kubectl/describe.go b/pkg/kubectl/describe.go index 453ab2da7e..c30d67c531 100644 --- a/pkg/kubectl/describe.go +++ b/pkg/kubectl/describe.go @@ -845,7 +845,7 @@ func (d *ReplicationControllerDescriber) Describe(namespace, name string) (strin return "", err } - running, waiting, succeeded, failed, err := getPodStatusForController(pc, controller.Spec.Selector) + running, waiting, succeeded, failed, err := getPodStatusForController(pc, labels.SelectorFromSet(controller.Spec.Selector)) if err != nil { return "", err } @@ -927,7 +927,11 @@ func (d *DaemonSetDescriber) Describe(namespace, name string) (string, error) { return "", err } - running, waiting, succeeded, failed, err := getPodStatusForController(pc, daemon.Spec.Selector) + selector, err := extensions.PodSelectorAsSelector(daemon.Spec.Selector) + if err != nil { + return "", err + } + running, waiting, succeeded, failed, err := getPodStatusForController(pc, selector) if err != nil { return "", err } @@ -945,7 +949,12 @@ func describeDaemonSet(daemon *extensions.DaemonSet, events *api.EventList, runn } else { fmt.Fprintf(out, "Image(s):\t%s\n", "") } - fmt.Fprintf(out, "Selector:\t%s\n", labels.FormatLabels(daemon.Spec.Selector)) + selector, err := extensions.PodSelectorAsSelector(daemon.Spec.Selector) + if err != nil { + // this shouldn't happen if PodSelector passed validation + return err + } + fmt.Fprintf(out, "Selector:\t%s\n", selector) fmt.Fprintf(out, "Node-Selector:\t%s\n", labels.FormatLabels(daemon.Spec.Template.Spec.NodeSelector)) fmt.Fprintf(out, "Labels:\t%s\n", labels.FormatLabels(daemon.Labels)) fmt.Fprintf(out, "Desired Number of Nodes Scheduled: %d\n", daemon.Status.DesiredNumberScheduled) @@ -1575,7 +1584,11 @@ func getDaemonSetsForLabels(c client.DaemonSetInterface, labelsToMatch labels.La // Find the ones that match labelsToMatch. var matchingDaemonSets []extensions.DaemonSet for _, ds := range dss.Items { - selector := labels.SelectorFromSet(ds.Spec.Selector) + selector, err := extensions.PodSelectorAsSelector(ds.Spec.Selector) + if err != nil { + // this should never happen if the DaemonSet passed validation + return nil, err + } if selector.Matches(labelsToMatch) { matchingDaemonSets = append(matchingDaemonSets, ds) } @@ -1620,8 +1633,8 @@ func printReplicationControllersByLabels(matchingRCs []*api.ReplicationControlle return list } -func getPodStatusForController(c client.PodInterface, selector map[string]string) (running, waiting, succeeded, failed int, err error) { - rcPods, err := c.List(labels.SelectorFromSet(selector), fields.Everything()) +func getPodStatusForController(c client.PodInterface, selector labels.Selector) (running, waiting, succeeded, failed int, err error) { + rcPods, err := c.List(selector, fields.Everything()) if err != nil { return } diff --git a/pkg/kubectl/resource_printer.go b/pkg/kubectl/resource_printer.go index 397979f198..77d1085bfe 100644 --- a/pkg/kubectl/resource_printer.go +++ b/pkg/kubectl/resource_printer.go @@ -931,11 +931,16 @@ func printDaemonSet(ds *extensions.DaemonSet, w io.Writer, withNamespace bool, w return err } } + selector, err := extensions.PodSelectorAsSelector(ds.Spec.Selector) + if err != nil { + // this shouldn't happen if PodSelector passed validation + return err + } if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s", name, firstContainer.Name, firstContainer.Image, - labels.FormatLabels(ds.Spec.Selector), + selector, labels.FormatLabels(ds.Spec.Template.Spec.NodeSelector), ); err != nil { return err diff --git a/pkg/registry/daemonset/etcd/etcd_test.go b/pkg/registry/daemonset/etcd/etcd_test.go index 8ac9ac2523..c1bdf5fb3e 100755 --- a/pkg/registry/daemonset/etcd/etcd_test.go +++ b/pkg/registry/daemonset/etcd/etcd_test.go @@ -42,7 +42,7 @@ func newValidDaemonSet() *extensions.DaemonSet { Namespace: api.NamespaceDefault, }, Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{"a": "b"}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{"a": "b"}}, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"a": "b"}, @@ -76,7 +76,7 @@ func TestCreate(t *testing.T) { // invalid (invalid selector) &extensions.DaemonSet{ Spec: extensions.DaemonSetSpec{ - Selector: map[string]string{}, + Selector: &extensions.PodSelector{MatchLabels: map[string]string{}}, Template: validDaemonSet.Spec.Template, }, }, @@ -113,7 +113,7 @@ func TestUpdate(t *testing.T) { }, func(obj runtime.Object) runtime.Object { object := obj.(*extensions.DaemonSet) - object.Spec.Selector = map[string]string{} + object.Spec.Selector = &extensions.PodSelector{MatchLabels: map[string]string{}} return object }, ) diff --git a/test/e2e/daemon_set.go b/test/e2e/daemon_set.go index 403d84d30e..d88025ea66 100644 --- a/test/e2e/daemon_set.go +++ b/test/e2e/daemon_set.go @@ -134,7 +134,7 @@ var _ = Describe("Daemon set", func() { Name: dsName, }, Spec: extensions.DaemonSetSpec{ - Selector: complexLabel, + Selector: &extensions.PodSelector{MatchLabels: complexLabel}, Template: &api.PodTemplateSpec{ ObjectMeta: api.ObjectMeta{ Labels: complexLabel,