Support default types in the resource builder

Right now there is no method in the resource builder for specifying just the name of a resource. NameParam is useful when a default type is already specified with ResourceTypes.

Signed-off-by: kargakis <mkargaki@redhat.com>
pull/6/head
kargakis 2015-07-09 11:05:13 +02:00 committed by kargakis
parent 4d10def14f
commit f3c63ba16b
2 changed files with 77 additions and 9 deletions

View File

@ -184,6 +184,28 @@ func (b *Builder) ResourceTypes(types ...string) *Builder {
return b
}
// ResourceNames accepts a default type and one or more names, and creates tuples of
// resources
func (b *Builder) ResourceNames(resource string, names ...string) *Builder {
for _, name := range names {
// See if this input string is of type/name format
tuple, ok, err := splitResourceTypeName(name)
if err != nil {
b.errs = append(b.errs, err)
return b
}
if ok {
b.resourceTuples = append(b.resourceTuples, tuple)
continue
}
// Use the given default type to create a resource tuple
b.resourceTuples = append(b.resourceTuples, resourceTuple{Resource: resource, Name: name})
}
return b
}
// SelectorParam defines a selector that should be applied to the object types to load.
// This will not affect files loaded from disk or URL. If the parameter is empty it is
// a no-op - to select all resources invoke `b.Selector(labels.Everything)`.
@ -279,17 +301,14 @@ func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string
return b
}
for _, s := range args {
seg := strings.Split(s, "/")
if len(seg) != 2 {
b.errs = append(b.errs, fmt.Errorf("arguments in resource/name form may not have more than one slash"))
tuple, ok, err := splitResourceTypeName(s)
if err != nil {
b.errs = append(b.errs, err)
return b
}
resource, name := seg[0], seg[1]
if len(resource) == 0 || len(name) == 0 || len(SplitResourceArgument(resource)) != 1 {
b.errs = append(b.errs, fmt.Errorf("arguments in resource/name form must have a single resource and name"))
return b
if ok {
b.resourceTuples = append(b.resourceTuples, tuple)
}
b.resourceTuples = append(b.resourceTuples, resourceTuple{Resource: resource, Name: name})
}
return b
}
@ -346,6 +365,23 @@ func hasCombinedTypeArgs(args []string) (bool, error) {
}
}
// splitResourceTypeName handles type/name resource formats and returns a resource tuple
// (empty or not), whether it successfully found one, and an error
func splitResourceTypeName(s string) (resourceTuple, bool, error) {
if !strings.Contains(s, "/") {
return resourceTuple{}, false, nil
}
seg := strings.Split(s, "/")
if len(seg) != 2 {
return resourceTuple{}, false, fmt.Errorf("arguments in resource/name form may not have more than one slash")
}
resource, name := seg[0], seg[1]
if len(resource) == 0 || len(name) == 0 || len(SplitResourceArgument(resource)) != 1 {
return resourceTuple{}, false, fmt.Errorf("arguments in resource/name form must have a single resource and name")
}
return resourceTuple{Resource: resource, Name: name}, true, nil
}
// Flatten will convert any objects with a field named "Items" that is an array of runtime.Object
// compatible types into individual entries and give them their own items. The original object
// is not passed to any visitors.

View File

@ -114,6 +114,10 @@ func testData() (*api.PodList, *api.ServiceList) {
Items: []api.Service{
{
ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"},
Spec: api.ServiceSpec{
Type: "ClusterIP",
SessionAffinity: "None",
},
},
},
}
@ -374,7 +378,7 @@ func TestResourceByName(t *testing.T) {
t.Fatalf("unexpected response: %v %t %#v", err, singular, test.Infos)
}
if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
t.Errorf("unexpected object: %#v", test.Objects())
t.Errorf("unexpected object: %#v", test.Objects()[0])
}
mapping, err := b.Do().ResourceMapping()
@ -418,6 +422,34 @@ func TestMultipleResourceByTheSameName(t *testing.T) {
}
}
func TestResourceNames(t *testing.T) {
pods, svc := testData()
b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(latest.Codec, &pods.Items[0]),
"/namespaces/test/services/baz": runtime.EncodeOrDie(latest.Codec, &svc.Items[0]),
})).
NamespaceParam("test")
test := &testVisitor{}
if b.Do().Err() == nil {
t.Errorf("unexpected non-error")
}
b.ResourceNames("pods", "foo", "services/baz")
err := b.Do().Visit(test.Handle)
if err != nil || len(test.Infos) != 2 {
t.Fatalf("unexpected response: %v %#v", err, test.Infos)
}
if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[0], &pods.Items[0])
}
if !reflect.DeepEqual(&svc.Items[0], test.Objects()[1]) {
t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[1], &svc.Items[0])
}
}
func TestResourceByNameWithoutRequireObject(t *testing.T) {
b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClientWith("", t, map[string]string{})).
NamespaceParam("test")