// getResourceKind returns the external group version kind registered for the given storage // object. If the storage object is a subresource and has an override supplied for it, it returns // the group version kind supplied in the override. func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, error) { if fqKindToRegister, ok := a.group.SubresourceGroupVersionKind[path]; ok { return fqKindToRegister, nil } object := storage.New() fqKinds, _, err := a.group.Typer.ObjectKinds(object) if err != nil { return schema.GroupVersionKind{}, err } // a given go type can have multiple potential fully qualified kinds. Find the one that corresponds with the group // we're trying to register here fqKindToRegister := schema.GroupVersionKind{} for _, fqKind := range fqKinds { if fqKind.Group == a.group.GroupVersion.Group { fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind) break } // TODO This keeps it doing what it was doing before, but it doesn't feel right. if fqKind.Group == extensions.GroupName && fqKind.Kind == "ThirdPartyResourceData" { fqKindToRegister = a.group.GroupVersion.WithKind(fqKind.Kind) } } if fqKindToRegister.Empty() { return schema.GroupVersionKind{}, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion) } return fqKindToRegister, nil }
// RunExplain executes the appropriate steps to print a model's documentation func RunExplain(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string) error { if len(args) == 0 { fmt.Fprint(cmdErr, "You must specify the type of resource to explain. ", valid_resources) return cmdutil.UsageError(cmd, "Required resource not specified.") } if len(args) > 1 { return cmdutil.UsageError(cmd, "We accept only this format: explain RESOURCE") } recursive := cmdutil.GetFlagBool(cmd, "recursive") apiVersionString := cmdutil.GetFlagString(cmd, "api-version") apiVersion := schema.GroupVersion{} mapper, _ := f.Object() // TODO: After we figured out the new syntax to separate group and resource, allow // the users to use it in explain (kubectl explain <group><syntax><resource>). // Refer to issue #16039 for why we do this. Refer to PR #15808 that used "/" syntax. inModel, fieldsPath, err := kubectl.SplitAndParseResourceRequest(args[0], mapper) if err != nil { return err } // TODO: We should deduce the group for a resource by discovering the supported resources at server. fullySpecifiedGVR, groupResource := schema.ParseResourceArg(inModel) gvk := schema.GroupVersionKind{} if fullySpecifiedGVR != nil { gvk, _ = mapper.KindFor(*fullySpecifiedGVR) } if gvk.Empty() { gvk, err = mapper.KindFor(groupResource.WithVersion("")) if err != nil { return err } } if len(apiVersionString) == 0 { groupMeta, err := api.Registry.Group(gvk.Group) if err != nil { return err } apiVersion = groupMeta.GroupVersion } else { apiVersion, err = schema.ParseGroupVersion(apiVersionString) if err != nil { return nil } } schema, err := f.SwaggerSchema(apiVersion.WithKind(gvk.Kind)) if err != nil { return err } return kubectl.PrintModelDescription(inModel, fieldsPath, out, schema, recursive) }
// mappingFor returns the RESTMapping for the Kind referenced by the resource. // prefers a fully specified GroupVersionResource match. If we don't have one match on GroupResource func (b *Builder) mappingFor(resourceArg string) (*meta.RESTMapping, error) { fullySpecifiedGVR, groupResource := schema.ParseResourceArg(resourceArg) gvk := schema.GroupVersionKind{} if fullySpecifiedGVR != nil { gvk, _ = b.mapper.KindFor(*fullySpecifiedGVR) } if gvk.Empty() { var err error gvk, err = b.mapper.KindFor(groupResource.WithVersion("")) if err != nil { return nil, err } } return b.mapper.RESTMapping(gvk.GroupKind(), gvk.Version) }