func IsThirdPartyObject(rawData []byte, gvk *schema.GroupVersionKind) (isThirdParty bool, gvkOut *schema.GroupVersionKind, err error) { var gv schema.GroupVersion if gvk == nil { data, err := yaml.ToJSON(rawData) if err != nil { return false, nil, err } metadata := metav1.TypeMeta{} if err = json.Unmarshal(data, &metadata); err != nil { return false, nil, err } gv, err = schema.ParseGroupVersion(metadata.APIVersion) if err != nil { return false, nil, err } gvkOut = &schema.GroupVersionKind{ Group: gv.Group, Version: gv.Version, Kind: metadata.Kind, } } else { gv = gvk.GroupVersion() gvkOut = gvk } return registered.IsThirdPartyAPIGroupVersion(gv), gvkOut, nil }
// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind // in the GroupVersionKind may be empty. func (c *clientPoolImpl) ClientForGroupVersionKind(kind schema.GroupVersionKind) (*Client, error) { c.lock.Lock() defer c.lock.Unlock() gv := kind.GroupVersion() // do we have a client already configured? if existingClient, found := c.clients[gv]; found { return existingClient, nil } // avoid changing the original config confCopy := *c.config conf := &confCopy // we need to set the api path based on group version, if no group, default to legacy path conf.APIPath = c.apiPathResolverFunc(kind) // we need to make a client conf.GroupVersion = &gv dynamicClient, err := NewClient(conf) if err != nil { return nil, err } c.clients[gv] = dynamicClient return dynamicClient, nil }
// 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 }
// checkNamespace makes sure that the scope of gvk matches ns. It // returns an error if namespace is empty but gvk is a namespaced // kind, or if ns is non-empty and gvk is a namespaced kind. func checkNamespace(gvk schema.GroupVersionKind, ns string) error { group, err := registered.Group(gvk.Group) if err != nil { return err } mapping, err := group.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version) if err != nil { return err } switch mapping.Scope.Name() { case meta.RESTScopeNameRoot: if ns != "" { return fmt.Errorf("namespace specified for a non-namespaced kind %s", gvk) } case meta.RESTScopeNameNamespace: if ns == "" { // Skipping this check for Events, since // controllers emit events that have no namespace, // even though Event is a namespaced resource. if gvk.Kind != "Event" { return fmt.Errorf("no namespace specified for a namespaced kind %s", gvk) } } } return nil }
func (f *factory) SwaggerSchema(gvk schema.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() discovery, err := f.DiscoveryClient() if err != nil { return nil, err } return discovery.SwaggerSchema(version) }
func (f *factory) SwaggerSchema(gvk schema.GroupVersionKind) (*swagger.ApiDeclaration, error) { version := gvk.GroupVersion() clientset, err := f.clients.ClientSetForVersion(&version) if err != nil { return nil, err } return clientset.Discovery().SwaggerSchema(version) }
// 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 := registered.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) }
// copyKindDefaults defaults dst to the value in src if dst does not have a value set. func copyKindDefaults(dst, src *schema.GroupVersionKind) { if src == nil { return } // apply kind and version defaulting from provided default if len(dst.Kind) == 0 { dst.Kind = src.Kind } if len(dst.Version) == 0 && len(src.Version) > 0 { dst.Group = src.Group dst.Version = src.Version } }
// 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) }
func doDeepCopyTest(t *testing.T, kind schema.GroupVersionKind, f *fuzz.Fuzzer) { item, err := api.Scheme.New(kind) if err != nil { t.Fatalf("Could not create a %v: %s", kind, err) } f.Fuzz(item) itemCopy, err := api.Scheme.DeepCopy(item) if err != nil { t.Errorf("Could not deep copy a %v: %s", kind, err) return } if !reflect.DeepEqual(item, itemCopy) { t.Errorf("\nexpected: %#v\n\ngot: %#v\n\ndiff: %v", item, itemCopy, diff.ObjectReflectDiff(item, itemCopy)) } prefuzzData := &bytes.Buffer{} if err := api.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, prefuzzData); err != nil { t.Errorf("Could not encode a %v: %s", kind, err) return } // Refuzz the copy, which should have no effect on the original f.Fuzz(itemCopy) postfuzzData := &bytes.Buffer{} if err := api.Codecs.LegacyCodec(kind.GroupVersion()).Encode(item, postfuzzData); err != nil { t.Errorf("Could not encode a %v: %s", kind, err) return } if bytes.Compare(prefuzzData.Bytes(), postfuzzData.Bytes()) != 0 { t.Log(diff.StringDiff(prefuzzData.String(), postfuzzData.String())) t.Errorf("Fuzzing copy modified original of %#v", kind) return } }
// KindToResource converts Kind to a resource name. // Broken. This method only "sort of" works when used outside of this package. It assumes that Kinds and Resources match // and they aren't guaranteed to do so. func KindToResource(kind schema.GroupVersionKind) ( /*plural*/ schema.GroupVersionResource /*singular*/, schema.GroupVersionResource) { kindName := kind.Kind if len(kindName) == 0 { return schema.GroupVersionResource{}, schema.GroupVersionResource{} } singularName := strings.ToLower(kindName) singular := kind.GroupVersion().WithResource(singularName) for _, skip := range unpluralizedSuffixes { if strings.HasSuffix(singularName, skip) { return singular, singular } } switch string(singularName[len(singularName)-1]) { case "s": return kind.GroupVersion().WithResource(singularName + "es"), singular case "y": return kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies"), singular } return kind.GroupVersion().WithResource(singularName + "s"), singular }
func (t *thirdPartyResourceDataCreator) New(kind schema.GroupVersionKind) (out runtime.Object, err error) { switch kind.Kind { case "ThirdPartyResourceData": if apiutil.GetGroupVersion(t.group, t.version) != kind.GroupVersion().String() { return nil, fmt.Errorf("unknown kind %v", kind) } return &extensions.ThirdPartyResourceData{}, nil case "ThirdPartyResourceDataList": if apiutil.GetGroupVersion(t.group, t.version) != kind.GroupVersion().String() { return nil, fmt.Errorf("unknown kind %v", kind) } return &extensions.ThirdPartyResourceDataList{}, nil // TODO: this list needs to be formalized higher in the chain case "ListOptions", "WatchEvent": if apiutil.GetGroupVersion(t.group, t.version) == kind.GroupVersion().String() { // Translate third party group to external group. gvk := registered.EnabledVersionsForGroup(api.GroupName)[0].WithKind(kind.Kind) return t.delegate.New(gvk) } return t.delegate.New(kind) default: return t.delegate.New(kind) } }
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta func (obj *TypeMeta) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() }
func (obj *ExternalType2) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() }
// RESTMapping returns a struct representing the resource path and conversion interfaces a // RESTClient should use to operate on the provided group/kind in order of versions. If a version search // order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which // version should be used to access the named group/kind. // TODO: consider refactoring to use RESTMappings in a way that preserves version ordering and preference func (m *DefaultRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) { // Pick an appropriate version var gvk *schema.GroupVersionKind hadVersion := false for _, version := range versions { if len(version) == 0 || version == runtime.APIVersionInternal { continue } currGVK := gk.WithVersion(version) hadVersion = true if _, ok := m.kindToPluralResource[currGVK]; ok { gvk = &currGVK break } } // Use the default preferred versions if !hadVersion && (gvk == nil) { for _, gv := range m.defaultGroupVersions { if gv.Group != gk.Group { continue } currGVK := gk.WithVersion(gv.Version) if _, ok := m.kindToPluralResource[currGVK]; ok { gvk = &currGVK break } } } if gvk == nil { return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")} } // Ensure we have a REST mapping resource, ok := m.kindToPluralResource[*gvk] if !ok { found := []schema.GroupVersion{} for _, gv := range m.defaultGroupVersions { if _, ok := m.kindToPluralResource[*gvk]; ok { found = append(found, gv) } } if len(found) > 0 { return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", gvk.Kind, found, gvk.GroupVersion().String()) } return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", gvk.GroupVersion().String(), gvk.Kind) } // Ensure we have a REST scope scope, ok := m.kindToScope[*gvk] if !ok { return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind) } interfaces, err := m.interfacesFunc(gvk.GroupVersion()) if err != nil { return nil, fmt.Errorf("the provided version %q has no relevant versions: %v", gvk.GroupVersion().String(), err) } retVal := &RESTMapping{ Resource: resource.Resource, GroupVersionKind: *gvk, Scope: scope, ObjectConvertor: interfaces.ObjectConvertor, MetadataAccessor: interfaces.MetadataAccessor, } return retVal, nil }
func (obj *Config) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() }
// IsAnAPIObject allows clients to preemptively get a reference to an API object and pass it to places that // intend only to get a reference to that object. This simplifies the event recording interface. func (obj *ObjectReference) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() }
func (obj *MyAPIObject) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind() }
func (t *thirdPartyResourceDataDecoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { if into == nil { if gvk == nil || gvk.Kind != t.kind { if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { return nil, nil, err } else if !isThirdParty { return t.delegate.Decode(data, gvk, into) } } return t.populate(data) } switch o := into.(type) { case *extensions.ThirdPartyResourceData: break case *runtime.VersionedObjects: // We're not sure that it's third party, we need to test if gvk == nil || gvk.Kind != t.kind { if isThirdParty, _, err := IsThirdPartyObject(data, gvk); err != nil { return nil, nil, err } else if !isThirdParty { return t.delegate.Decode(data, gvk, into) } } obj, outGVK, err := t.populate(data) if err != nil { return nil, nil, err } o.Objects = []runtime.Object{ obj, } return o, outGVK, nil default: if gvk != nil && registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // delegate won't recognize a thirdparty group version gvk = nil } return t.delegate.Decode(data, gvk, into) } thirdParty := into.(*extensions.ThirdPartyResourceData) var dataObj interface{} if err := json.Unmarshal(data, &dataObj); err != nil { return nil, nil, err } mapObj, ok := dataObj.(map[string]interface{}) if !ok { return nil, nil, fmt.Errorf("unexpected object: %#v", dataObj) } /*if gvk.Kind != "ThirdPartyResourceData" { return nil, nil, fmt.Errorf("unexpected kind: %s", gvk.Kind) }*/ actual := &schema.GroupVersionKind{} if kindObj, found := mapObj["kind"]; !found { if gvk == nil { return nil, nil, runtime.NewMissingKindErr(string(data)) } mapObj["kind"] = gvk.Kind actual.Kind = gvk.Kind } else { kindStr, ok := kindObj.(string) if !ok { return nil, nil, fmt.Errorf("unexpected object for 'kind': %v", kindObj) } if len(t.kind) > 0 && kindStr != t.kind { return nil, nil, fmt.Errorf("kind doesn't match, expecting: %s, got %s", t.kind, kindStr) } actual.Kind = kindStr } if versionObj, found := mapObj["apiVersion"]; !found { if gvk == nil { return nil, nil, runtime.NewMissingVersionErr(string(data)) } mapObj["apiVersion"] = gvk.GroupVersion().String() actual.Group, actual.Version = gvk.Group, gvk.Version } else { versionStr, ok := versionObj.(string) if !ok { return nil, nil, fmt.Errorf("unexpected object for 'apiVersion': %v", versionObj) } if gvk != nil && versionStr != gvk.GroupVersion().String() { return nil, nil, fmt.Errorf("version doesn't match, expecting: %v, got %s", gvk.GroupVersion(), versionStr) } gv, err := schema.ParseGroupVersion(versionStr) if err != nil { return nil, nil, err } actual.Group, actual.Version = gv.Group, gv.Version } mapObj, err := parseObject(data) if err != nil { return nil, actual, err } if err := t.populateResource(thirdParty, mapObj, data); err != nil { return nil, actual, err } return thirdParty, actual, nil }
func (c *mockCreater) New(kind schema.GroupVersionKind) (runtime.Object, error) { c.apiVersion, c.kind = kind.GroupVersion().String(), kind.Kind return c.obj, c.err }
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk schema.GroupVersionKind) { obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind() }
func (u *UnstructuredList) SetGroupVersionKind(gvk schema.GroupVersionKind) { u.SetAPIVersion(gvk.GroupVersion().String()) u.SetKind(gvk.Kind) }