move daemonset to generalized label selector

pull/6/head
Mike Danese 2015-10-25 23:11:09 -07:00
parent abbed4f7e8
commit 7a7f31ead1
13 changed files with 91 additions and 64 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -185,18 +185,18 @@ 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) {
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")...)
@ -204,7 +204,7 @@ func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec) errs.ValidationErrorL
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)...)
}

View File

@ -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,

View File

@ -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)) {

View File

@ -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"}},
},
},
},

View File

@ -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
}

View File

@ -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,

View File

@ -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", "<no template>")
}
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
}

View File

@ -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

View File

@ -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
},
)

View File

@ -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,