mirror of https://github.com/k3s-io/k3s
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
parent
4d10def14f
commit
f3c63ba16b
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue