From 9417fc2867f2d33c4b14304f292930c95d3bf0c2 Mon Sep 17 00:00:00 2001 From: wangxinyi7 <121973291+wangxinyi7@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:53:51 -0700 Subject: [PATCH] gvk partial inference (#19058) * gvk partial inference --- command/resource/delete/delete.go | 4 -- command/resource/delete/delete_test.go | 2 +- command/resource/helper.go | 83 ++++++++++++++++++-------- command/resource/read/read_test.go | 2 +- 4 files changed, 59 insertions(+), 32 deletions(-) diff --git a/command/resource/delete/delete.go b/command/resource/delete/delete.go index 2679951da8b1..06421d6d1e2d 100644 --- a/command/resource/delete/delete.go +++ b/command/resource/delete/delete.go @@ -84,10 +84,6 @@ func (c *cmd) Run(args []string) int { return 1 } } else { - if len(args) < 2 { - c.UI.Error("Incorrect argument format: Must specify two arguments: resource type and resource name") - return 1 - } var err error gvk, resourceName, err = resource.GetTypeAndResourceName(args) if err != nil { diff --git a/command/resource/delete/delete_test.go b/command/resource/delete/delete_test.go index f888bb3c8fd5..7454455c941e 100644 --- a/command/resource/delete/delete_test.go +++ b/command/resource/delete/delete_test.go @@ -67,7 +67,7 @@ func TestResourceDeleteInvalidArgs(t *testing.T) { "invalid resource type format": { args: []string{"a.", "name", "-namespace", "default"}, expectedCode: 1, - expectedErr: errors.New("Incorrect argument format: Must include resource type argument in group.verion.kind format"), + expectedErr: errors.New("Must provide resource type argument with either in group.verion.kind format or its shorthand name"), }, } diff --git a/command/resource/helper.go b/command/resource/helper.go index 417144ac7896..221a018599a7 100644 --- a/command/resource/helper.go +++ b/command/resource/helper.go @@ -96,21 +96,7 @@ func parseJson(js string) (*pbresource.Resource, error) { } func ParseResourceFromFile(filePath string) (*pbresource.Resource, error) { - data, err := helpers.LoadDataSourceNoRaw(filePath, nil) - if err != nil { - return nil, fmt.Errorf("Failed to load data: %v", err) - } - var parsedResource *pbresource.Resource - if isHCL([]byte(data)) { - parsedResource, err = resourcehcl.Unmarshal([]byte(data), consul.NewTypeRegistry()) - } else { - parsedResource, err = parseJson(data) - } - if err != nil { - return nil, fmt.Errorf("Failed to decode resource from input file: %v", err) - } - - return parsedResource, nil + return ParseResourceInput(filePath, nil) } // this is an inlined variant of hcl.lexMode() @@ -165,23 +151,17 @@ func ParseInputParams(inputArgs []string, flags *flag.FlagSet) error { } func GetTypeAndResourceName(args []string) (gvk *GVK, resourceName string, e error) { + if len(args) < 2 { + return nil, "", fmt.Errorf("Must specify two arguments: resource type and resource name") + } // it has to be resource name after the type if strings.HasPrefix(args[1], "-") { return nil, "", fmt.Errorf("Must provide resource name right after type") } + resourceName = args[1] - s := strings.Split(args[0], ".") - if len(s) != 3 { - return nil, "", fmt.Errorf("Must include resource type argument in group.verion.kind format") - } - - gvk = &GVK{ - Group: s[0], - Version: s[1], - Kind: s[2], - } + gvk, e = inferGVKFromResourceType(args[0]) - resourceName = args[1] return } @@ -282,3 +262,54 @@ func (resource *Resource) List(gvk *GVK, q *client.QueryOptions) (*ListResponse, return out, nil } + +func inferGVKFromResourceType(resourceType string) (*GVK, error) { + s := strings.Split(resourceType, ".") + switch length := len(s); { + // only kind is provided + case length == 1: + kindToGVKMap := BuildKindToGVKMap() + kind := strings.ToLower(s[0]) + switch len(kindToGVKMap[kind]) { + // no g.v.k is found + case 0: + return nil, fmt.Errorf("The shorthand name does not map to any existing resource type, please check `consul api-resources`") + // only one is found + case 1: + // infer gvk from resource kind + gvkSplit := strings.Split(kindToGVKMap[kind][0], ".") + return &GVK{ + Group: gvkSplit[0], + Version: gvkSplit[1], + Kind: gvkSplit[2], + }, nil + // it alerts error if any conflict is found + default: + return nil, fmt.Errorf("The shorthand name has conflicts %v, please use the full name", kindToGVKMap[s[0]]) + } + case length == 3: + return &GVK{ + Group: s[0], + Version: s[1], + Kind: s[2], + }, nil + default: + return nil, fmt.Errorf("Must provide resource type argument with either in group.verion.kind format or its shorthand name") + } +} + +func BuildKindToGVKMap() map[string][]string { + // this use the local copy of registration to build map + typeRegistry := consul.NewTypeRegistry() + kindToGVKMap := map[string][]string{} + for _, r := range typeRegistry.Types() { + gvkString := fmt.Sprintf("%s.%s.%s", r.Type.Group, r.Type.GroupVersion, r.Type.Kind) + kindKey := strings.ToLower(r.Type.Kind) + if len(kindToGVKMap[kindKey]) == 0 { + kindToGVKMap[kindKey] = []string{gvkString} + } else { + kindToGVKMap[kindKey] = append(kindToGVKMap[kindKey], gvkString) + } + } + return kindToGVKMap +} diff --git a/command/resource/read/read_test.go b/command/resource/read/read_test.go index 766f86b02cc1..a293a9faf5e2 100644 --- a/command/resource/read/read_test.go +++ b/command/resource/read/read_test.go @@ -67,7 +67,7 @@ func TestResourceReadInvalidArgs(t *testing.T) { "invalid resource type format": { args: []string{"a.", "name", "-namespace", "default"}, expectedCode: 1, - expectedErr: errors.New("Incorrect argument format: Must include resource type argument in group.verion.kind format"), + expectedErr: errors.New("Incorrect argument format: Must provide resource type argument with either in group.verion.kind format or its shorthand name"), }, }