// SwaggerSchema retrieves and parses the swagger API schema the server supports. func (d *DiscoveryClient) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) { if version.Empty() { return nil, fmt.Errorf("groupVersion cannot be empty") } groupList, err := d.ServerGroups() if err != nil { return nil, err } groupVersions := unversioned.ExtractGroupVersions(groupList) // This check also takes care the case that kubectl is newer than the running endpoint if stringDoesntExistIn(version.String(), groupVersions) { return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions) } var path string if len(d.LegacyPrefix) > 0 && version == v1.SchemeGroupVersion { path = "/swaggerapi" + d.LegacyPrefix + "/" + version.Version } else { path = "/swaggerapi/apis/" + version.Group + "/" + version.Version } body, err := d.Get().AbsPath(path).Do().Raw() if err != nil { return nil, err } var schema swagger.ApiDeclaration err = json.Unmarshal(body, &schema) if err != nil { return nil, fmt.Errorf("got '%s': %v", string(body), err) } return &schema, nil }
// UnsafeConvertToVersion will convert in to the provided outVersion if such a conversion is possible, // but does not guarantee the output object does not share fields with the input object. It attempts to be as // efficient as possible when doing conversion. func (s *Scheme) UnsafeConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) { switch t := in.(type) { case *Unknown: t.APIVersion = outVersion.String() return t, nil case *Unstructured: t.SetAPIVersion(outVersion.String()) return t, nil case *UnstructuredList: t.SetAPIVersion(outVersion.String()) return t, nil } // determine the incoming kinds with as few allocations as possible. t := reflect.TypeOf(in) if t.Kind() != reflect.Ptr { return nil, fmt.Errorf("only pointer types may be converted: %v", t) } t = t.Elem() if t.Kind() != reflect.Struct { return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t) } kinds, ok := s.typeToGVK[t] if !ok || len(kinds) == 0 { return nil, fmt.Errorf("%v is not a registered type and cannot be converted into version %q", t, outVersion) } // if the Go type is also registered to the destination kind, no conversion is necessary for i := range kinds { if kinds[i].Version == outVersion.Version && kinds[i].Group == outVersion.Group { setTargetKind(in, kinds[i]) return in, nil } } // type is unversioned, no conversion necessary // it should be possible to avoid this allocation if unversionedKind, ok := s.unversionedTypes[t]; ok { kind := unversionedKind outKind := outVersion.WithKind(kind.Kind) setTargetKind(in, outKind) return in, nil } // allocate a new object as the target using the target kind // TODO: this should look in the target group version and find the first kind that matches, rather than the // first kind registered in typeToGVK kind := kinds[0] kind.Version = outVersion.Version kind.Group = outVersion.Group out, err := s.New(kind) if err != nil { return nil, err } // TODO: try to avoid the allocations here - in fast paths we are not likely to need these flags or meta flags, meta := s.converter.DefaultMeta(t) if err := s.converter.Convert(in, out, flags, meta); err != nil { return nil, err } setTargetKind(out, kind) return out, nil }