version field selector field names in the client

This commit is contained in:
Daniel Smith 2015-04-07 12:05:38 -07:00
parent 71e7079aea
commit c1390a0836
4 changed files with 88 additions and 41 deletions

View File

@ -248,36 +248,85 @@ func (r *Request) RequestURI(uri string) *Request {
return r
}
/*
// ParseSelectorParam parses the given string as a resource selector.
// This is a convenience function so you don't have to first check that it's a
// validly formatted selector.
func (r *Request) ParseSelectorParam(paramName, item string) *Request {
if r.err != nil {
return r
const (
// A constant that clients can use to refer in a field selector to the object name field.
// Will be automatically emitted as the correct name for the API version.
ObjectNameField = "metadata.name"
PodHost = "spec.host"
)
type clientFieldNameToAPIVersionFieldName map[string]string
func (c clientFieldNameToAPIVersionFieldName) filterField(field, value string) (newField, newValue string, err error) {
newFieldName, ok := c[field]
if !ok {
return "", "", fmt.Errorf("%v - %v - no field mapping defined", field, value)
}
var selector string
var err error
switch paramName {
case "labels":
var lsel labels.Selector
if lsel, err = labels.Parse(item); err == nil {
selector = lsel.String()
}
case "fields":
var fsel fields.Selector
if fsel, err = fields.ParseSelector(item); err == nil {
selector = fsel.String()
}
default:
err = fmt.Errorf("unknown parameter name '%s'", paramName)
return newFieldName, value, nil
}
type resourceTypeToFieldMapping map[string]clientFieldNameToAPIVersionFieldName
func (r resourceTypeToFieldMapping) filterField(resourceType, field, value string) (newField, newValue string, err error) {
fMapping, ok := r[resourceType]
if !ok {
return "", "", fmt.Errorf("%v - %v - %v - no field mapping defined", resourceType, field, value)
}
return fMapping.filterField(field, value)
}
type versionToResourceToFieldMapping map[string]resourceTypeToFieldMapping
func (v versionToResourceToFieldMapping) filterField(apiVersion, resourceType, field, value string) (newField, newValue string, err error) {
rMapping, ok := v[apiVersion]
if !ok {
glog.Warningf("field selector: %v - %v - %v - %v: need to check if this is versioned correctly.", apiVersion, resourceType, field, value)
return field, value, nil
}
newField, newValue, err = rMapping.filterField(resourceType, field, value)
if err != nil {
r.err = err
return r
// This is only a warning until we find and fix all of the client's usages.
glog.Warningf("field selector: %v - %v - %v - %v: need to check if this is versioned correctly.", apiVersion, resourceType, field, value)
return field, value, nil
}
return r.setParam(paramName, selector)
}*/
return newField, newValue, nil
}
var fieldMappings = versionToResourceToFieldMapping{
"v1beta1": resourceTypeToFieldMapping{
"nodes": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "name",
},
"minions": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "name",
},
"pods": clientFieldNameToAPIVersionFieldName{
PodHost: "DesiredState.Host",
},
},
"v1beta2": resourceTypeToFieldMapping{
"nodes": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "name",
},
"minions": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "name",
},
"pods": clientFieldNameToAPIVersionFieldName{
PodHost: "DesiredState.Host",
},
},
"v1beta3": resourceTypeToFieldMapping{
"nodes": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "metadata.name",
},
"minions": clientFieldNameToAPIVersionFieldName{
ObjectNameField: "metadata.name",
},
"pods": clientFieldNameToAPIVersionFieldName{
PodHost: "spec.host",
},
},
}
// FieldsSelectorParam adds the given selector as a query parameter with the name paramName.
func (r *Request) FieldsSelectorParam(s fields.Selector) *Request {
@ -287,7 +336,14 @@ func (r *Request) FieldsSelectorParam(s fields.Selector) *Request {
if s.Empty() {
return r
}
return r.setParam(api.FieldSelectorQueryParam(r.apiVersion), s.String())
s2, err := s.Transform(func(field, value string) (newField, newValue string, err error) {
return fieldMappings.filterField(r.apiVersion, r.resource, field, value)
})
if err != nil {
r.err = err
return r
}
return r.setParam(api.FieldSelectorQueryParam(r.apiVersion), s2.String())
}
// LabelsSelectorParam adds the given selector as a query parameter

View File

@ -28,8 +28,8 @@ import (
)
// NewSourceApiserver creates a config source that watches and pulls from the apiserver.
func NewSourceApiserver(client *client.Client, hostname string, updates chan<- interface{}) {
lw := cache.NewListWatchFromClient(client, "pods", api.NamespaceAll, fields.OneTermEqualSelector(getHostFieldLabel(client.APIVersion()), hostname))
func NewSourceApiserver(c *client.Client, hostname string, updates chan<- interface{}) {
lw := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.OneTermEqualSelector(client.PodHost, hostname))
newSourceApiserverFromLW(lw, updates)
}

View File

@ -168,7 +168,7 @@ func NewMainKubelet(
if kubeClient != nil {
// TODO: cache.NewListWatchFromClient is limited as it takes a client implementation rather
// than an interface. There is no way to construct a list+watcher using resource name.
fieldSelector := fields.Set{"metadata.name": hostname}.AsSelector()
fieldSelector := fields.Set{client.ObjectNameField: hostname}.AsSelector()
listWatch := &cache.ListWatch{
ListFunc: func() (runtime.Object, error) {
// TODO: Use List() with fieldSelector when it is supported.

View File

@ -208,7 +208,7 @@ func (f *ConfigFactory) CreateFromKeys(predicateKeys, priorityKeys util.StringSe
// Returns a cache.ListWatch that finds all pods that need to be
// scheduled.
func (factory *ConfigFactory) createUnassignedPodLW() *cache.ListWatch {
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, fields.Set{getHostFieldLabel(factory.Client.APIVersion()): ""}.AsSelector())
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll, fields.Set{client.PodHost: ""}.AsSelector())
}
func parseSelectorOrDie(s string) fields.Selector {
@ -224,7 +224,7 @@ func parseSelectorOrDie(s string) fields.Selector {
// TODO: return a ListerWatcher interface instead?
func (factory *ConfigFactory) createAssignedPodLW() *cache.ListWatch {
return cache.NewListWatchFromClient(factory.Client, "pods", api.NamespaceAll,
parseSelectorOrDie(getHostFieldLabel(factory.Client.APIVersion())+"!="))
parseSelectorOrDie(client.PodHost+"!="))
}
// createMinionLW returns a cache.ListWatch that gets all changes to minions.
@ -295,15 +295,6 @@ func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue
}
}
func getHostFieldLabel(apiVersion string) string {
switch apiVersion {
case "v1beta1", "v1beta2":
return "DesiredState.Host"
default:
return "spec.host"
}
}
// nodeEnumerator allows a cache.Poller to enumerate items in an api.NodeList
type nodeEnumerator struct {
*api.NodeList