// 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
}
Exemple #2
0
// 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
}