// ServerPreferredNamespacedGroupVersionResources uses the specified client to discover the set of preferred groupVersionResources that are namespaced
func ServerPreferredNamespacedGroupVersionResources(discoveryClient discovery.DiscoveryInterface) ([]unversioned.GroupVersionResource, error) {
	results := []unversioned.GroupVersionResource{}
	serverGroupList, err := discoveryClient.ServerGroups()
	if err != nil {
		return results, err
	}

	allErrs := []error{}
	for _, apiGroup := range serverGroupList.Groups {
		preferredVersion := apiGroup.PreferredVersion
		apiResourceList, err := discoveryClient.ServerResourcesForGroupVersion(preferredVersion.GroupVersion)
		if err != nil {
			allErrs = append(allErrs, err)
			continue
		}
		groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: preferredVersion.Version}
		for _, apiResource := range apiResourceList.APIResources {
			if !apiResource.Namespaced {
				continue
			}
			if strings.Contains(apiResource.Name, "/") {
				continue
			}
			results = append(results, groupVersion.WithResource(apiResource.Name))
		}
	}
	return results, utilerrors.NewAggregate(allErrs)
}
Example #2
0
func TestKindToResource(t *testing.T) {
	testCases := []struct {
		Kind             string
		Plural, Singular string
	}{
		{Kind: "Pod", Plural: "pods", Singular: "pod"},

		{Kind: "ReplicationController", Plural: "replicationcontrollers", Singular: "replicationcontroller"},

		// Add "ies" when ending with "y"
		{Kind: "ImageRepository", Plural: "imagerepositories", Singular: "imagerepository"},
		// Add "es" when ending with "s"
		{Kind: "miss", Plural: "misses", Singular: "miss"},
		// Add "s" otherwise
		{Kind: "lowercase", Plural: "lowercases", Singular: "lowercase"},
	}
	for i, testCase := range testCases {
		version := unversioned.GroupVersion{}

		plural, singular := KindToResource(version.WithKind(testCase.Kind))
		if singular != version.WithResource(testCase.Singular) || plural != version.WithResource(testCase.Plural) {
			t.Errorf("%d: unexpected plural and singular: %v %v", i, plural, singular)
		}
	}
}
Example #3
0
func TestRESTMapper(t *testing.T) {
	gv := unversioned.GroupVersion{Group: componentconfig.GroupName, Version: "v1alpha1"}
	proxyGVK := gv.WithKind("KubeProxyConfiguration")

	if gvk, err := registered.GroupOrDie(componentconfig.GroupName).RESTMapper.KindFor(gv.WithResource("kubeproxyconfiguration")); err != nil || gvk != proxyGVK {
		t.Errorf("unexpected version mapping: %v %v", gvk, err)
	}

	if m, err := registered.GroupOrDie(componentconfig.GroupName).RESTMapper.RESTMapping(proxyGVK.GroupKind(), ""); err != nil || m.GroupVersionKind != proxyGVK || m.Resource != "kubeproxyconfigurations" {
		t.Errorf("unexpected version mapping: %#v %v", m, err)
	}

	for _, version := range registered.GroupOrDie(componentconfig.GroupName).GroupVersions {
		mapping, err := registered.GroupOrDie(componentconfig.GroupName).RESTMapper.RESTMapping(proxyGVK.GroupKind(), version.Version)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			continue
		}

		if mapping.Resource != "kubeproxyconfigurations" {
			t.Errorf("incorrect resource name: %#v", mapping)
		}
		if mapping.GroupVersionKind.GroupVersion() != version {
			t.Errorf("incorrect groupVersion: %v", mapping)
		}

		interfaces, _ := registered.GroupOrDie(componentconfig.GroupName).InterfacesFor(version)
		if mapping.ObjectConvertor != interfaces.ObjectConvertor {
			t.Errorf("unexpected: %#v, expected: %#v", mapping, interfaces)
		}
	}
}
Example #4
0
// serverPreferredResources returns the supported resources with the version preferred by the
// server. If namespaced is true, only namespaced resources will be returned.
func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) {
	results := []unversioned.GroupVersionResource{}
	serverGroupList, err := d.ServerGroups()
	if err != nil {
		return results, err
	}

	var failedGroups map[unversioned.GroupVersion]error
	for _, apiGroup := range serverGroupList.Groups {
		preferredVersion := apiGroup.PreferredVersion
		groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: preferredVersion.Version}
		apiResourceList, err := d.ServerResourcesForGroupVersion(preferredVersion.GroupVersion)
		if err != nil {
			if failedGroups == nil {
				failedGroups = make(map[unversioned.GroupVersion]error)
			}
			failedGroups[groupVersion] = err
			continue
		}
		for _, apiResource := range apiResourceList.APIResources {
			// ignore the root scoped resources if "namespaced" is true.
			if namespaced && !apiResource.Namespaced {
				continue
			}
			if strings.Contains(apiResource.Name, "/") {
				continue
			}
			results = append(results, groupVersion.WithResource(apiResource.Name))
		}
	}
	if len(failedGroups) > 0 {
		return results, &ErrGroupDiscoveryFailed{Groups: failedGroups}
	}
	return results, nil
}
Example #5
0
// serverPreferredResources returns the supported resources with the version preferred by the
// server. If namespaced is true, only namespaced resources will be returned.
func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) {
	results := []unversioned.GroupVersionResource{}
	serverGroupList, err := d.ServerGroups()
	if err != nil {
		return results, err
	}

	allErrs := []error{}
	for _, apiGroup := range serverGroupList.Groups {
		preferredVersion := apiGroup.PreferredVersion
		apiResourceList, err := d.ServerResourcesForGroupVersion(preferredVersion.GroupVersion)
		if err != nil {
			allErrs = append(allErrs, err)
			continue
		}
		groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: preferredVersion.Version}
		for _, apiResource := range apiResourceList.APIResources {
			// ignore the root scoped resources if "namespaced" is true.
			if namespaced && !apiResource.Namespaced {
				continue
			}
			if strings.Contains(apiResource.Name, "/") {
				continue
			}
			results = append(results, groupVersion.WithResource(apiResource.Name))
		}
	}
	return results, utilerrors.NewAggregate(allErrs)
}
Example #6
0
// serverPreferredResources returns the supported resources with the version preferred by the
// server. If namespaced is true, only namespaced resources will be returned.
func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) {
	// retry in case the groups supported by the server change after ServerGroup() returns.
	const maxRetries = 2
	var failedGroups map[unversioned.GroupVersion]error
	var results []unversioned.GroupVersionResource
	var resources map[unversioned.GroupResource]string
RetrieveGroups:
	for i := 0; i < maxRetries; i++ {
		results = []unversioned.GroupVersionResource{}
		resources = map[unversioned.GroupResource]string{}
		failedGroups = make(map[unversioned.GroupVersion]error)
		serverGroupList, err := d.ServerGroups()
		if err != nil {
			return results, err
		}

		for _, apiGroup := range serverGroupList.Groups {
			versions := apiGroup.Versions
			for _, version := range versions {
				groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: version.Version}
				apiResourceList, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
				if err != nil {
					if i < maxRetries-1 {
						continue RetrieveGroups
					}
					failedGroups[groupVersion] = err
					continue
				}
				for _, apiResource := range apiResourceList.APIResources {
					// ignore the root scoped resources if "namespaced" is true.
					if namespaced && !apiResource.Namespaced {
						continue
					}
					if strings.Contains(apiResource.Name, "/") {
						continue
					}
					gvr := groupVersion.WithResource(apiResource.Name)
					if _, ok := resources[gvr.GroupResource()]; ok {
						if gvr.Version != apiGroup.PreferredVersion.Version {
							continue
						}
						// remove previous entry, because it will be replaced with a preferred one
						for i := range results {
							if results[i].GroupResource() == gvr.GroupResource() {
								results = append(results[:i], results[i+1:]...)
							}
						}
					}
					resources[gvr.GroupResource()] = gvr.Version
					results = append(results, gvr)
				}
			}
		}
		if len(failedGroups) == 0 {
			return results, nil
		}
	}
	return results, &ErrGroupDiscoveryFailed{Groups: failedGroups}
}
Example #7
0
// getBatchResources returns the resources for batch api
func (m *Master) getBatchResources(c *Config, version unversioned.GroupVersion) map[string]rest.Storage {
	storage := map[string]rest.Storage{}
	if c.APIResourceConfigSource.ResourceEnabled(version.WithResource("jobs")) {
		jobsStorage, jobsStatusStorage := jobetcd.NewREST(m.GetRESTOptionsOrDie(c, batch.Resource("jobs")))
		storage["jobs"] = jobsStorage
		storage["jobs/status"] = jobsStatusStorage
	}
	return storage
}
// serverPreferredResources returns the supported resources with the version preferred by the
// server. If namespaced is true, only namespaced resources will be returned.
func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) {
	// retry in case the groups supported by the server change after ServerGroup() returns.
	const maxRetries = 2
	var failedGroups map[unversioned.GroupVersion]error
	var results []unversioned.GroupVersionResource
RetrieveGroups:
	for i := 0; i < maxRetries; i++ {
		results = []unversioned.GroupVersionResource{}
		failedGroups = make(map[unversioned.GroupVersion]error)
		serverGroupList, err := d.ServerGroups()
		if err != nil {
			return results, err
		}

		for _, apiGroup := range serverGroupList.Groups {
			preferredVersion := apiGroup.PreferredVersion
			groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: preferredVersion.Version}
			apiResourceList, err := d.ServerResourcesForGroupVersion(preferredVersion.GroupVersion)
			if err != nil {
				if i < maxRetries-1 {
					continue RetrieveGroups
				}
				failedGroups[groupVersion] = err
				continue
			}
			for _, apiResource := range apiResourceList.APIResources {
				// ignore the root scoped resources if "namespaced" is true.
				if namespaced && !apiResource.Namespaced {
					continue
				}
				if strings.Contains(apiResource.Name, "/") {
					continue
				}
				results = append(results, groupVersion.WithResource(apiResource.Name))
			}
		}
		if len(failedGroups) == 0 {
			return results, nil
		}
	}
	return results, &ErrGroupDiscoveryFailed{Groups: failedGroups}
}
func TestDisabledVersion(t *testing.T) {
	g1v1 := unversioned.GroupVersion{Group: "group1", Version: "version1"}
	g1v2 := unversioned.GroupVersion{Group: "group1", Version: "version2"}
	g2v1 := unversioned.GroupVersion{Group: "group2", Version: "version1"}
	g3v1 := unversioned.GroupVersion{Group: "group3", Version: "version1"}

	resourceType := "the-resource"
	disabledResourceType := "the-disabled-resource"

	config := NewResourceConfig()

	config.DisableVersions(g1v1)
	config.EnableVersions(g1v2, g3v1)
	config.EnableResources(g1v1.WithResource(resourceType), g2v1.WithResource(resourceType))
	config.DisableResources(g1v2.WithResource(disabledResourceType))

	expectedEnabledResources := []unversioned.GroupVersionResource{
		g1v2.WithResource(resourceType),
		g2v1.WithResource(resourceType),
	}
	expectedDisabledResources := []unversioned.GroupVersionResource{
		g1v1.WithResource(resourceType), g1v1.WithResource(disabledResourceType),
		g1v2.WithResource(disabledResourceType),
		g2v1.WithResource(disabledResourceType),
	}

	for _, expectedResource := range expectedEnabledResources {
		if !config.ResourceEnabled(expectedResource) {
			t.Errorf("expected enabled for %v, from %v", expectedResource, config)
		}
	}
	for _, expectedResource := range expectedDisabledResources {
		if config.ResourceEnabled(expectedResource) {
			t.Errorf("expected disabled for %v, from %v", expectedResource, config)
		}
	}

	if e, a := false, config.AnyResourcesForVersionEnabled(g1v1); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}
	if e, a := false, config.AllResourcesForVersionEnabled(g1v1); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}
	if e, a := true, config.AnyResourcesForVersionEnabled(g1v2); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}
	if e, a := false, config.AllResourcesForVersionEnabled(g1v2); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}
	if e, a := true, config.AnyResourcesForVersionEnabled(g3v1); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}
	if e, a := true, config.AllResourcesForVersionEnabled(g3v1); e != a {
		t.Errorf("expected %v, got %v", e, a)
	}

	expectedEnabledAnyVersionResources := []unversioned.GroupResource{
		{Group: "group1", Resource: resourceType},
	}
	expectedDisabledAnyResources := []unversioned.GroupResource{
		{Group: "group1", Resource: disabledResourceType},
	}

	for _, expectedResource := range expectedEnabledAnyVersionResources {
		if !config.AnyVersionOfResourceEnabled(expectedResource) {
			t.Errorf("expected enabled for %v, from %v", expectedResource, config)
		}
	}
	for _, expectedResource := range expectedDisabledAnyResources {
		if config.AnyVersionOfResourceEnabled(expectedResource) {
			t.Errorf("expected disabled for %v, from %v", expectedResource, config)
		}
	}

}
Example #10
0
func (d *discoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
	d.initLock.Lock()
	defer d.initLock.Unlock()

	if d.delegate != nil {
		return d.delegate, nil
	}

	serverGroups, err := d.discoveryClient.ServerGroups()
	if err != nil {
		return nil, err
	}

	// always prefer our default group for now.  The version should be discovered from discovery, but this will hold us
	// for quite some time.
	resourcePriority := []unversioned.GroupVersionResource{
		{Group: kapi.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource},
	}
	kindPriority := []unversioned.GroupVersionKind{
		{Group: kapi.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind},
	}
	groupPriority := []string{}

	unionMapper := meta.MultiRESTMapper{}

	for _, group := range serverGroups.Groups {
		if len(group.Versions) == 0 {
			continue
		}
		groupPriority = append(groupPriority, group.Name)

		if len(group.PreferredVersion.Version) != 0 {
			preferredVersion := unversioned.GroupVersion{Group: group.Name, Version: group.PreferredVersion.Version}
			if registered.IsEnabledVersion(preferredVersion) {
				resourcePriority = append(resourcePriority, preferredVersion.WithResource(meta.AnyResource))
				kindPriority = append(kindPriority, preferredVersion.WithKind(meta.AnyKind))
			}
		}

		for _, discoveryVersion := range group.Versions {
			version := unversioned.GroupVersion{Group: group.Name, Version: discoveryVersion.Version}
			if !registered.IsEnabledVersion(version) {
				continue
			}
			groupMeta, err := registered.Group(group.Name)
			if err != nil {
				return nil, err
			}
			resources, err := d.discoveryClient.ServerResourcesForGroupVersion(version.String())
			if err != nil {
				return nil, err
			}

			versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{version}, groupMeta.InterfacesFor)
			for _, resource := range resources.APIResources {
				// TODO properly handle resource versus kind
				gvk := version.WithKind(resource.Kind)

				scope := meta.RESTScopeNamespace
				if !resource.Namespaced {
					scope = meta.RESTScopeRoot
				}
				versionMapper.Add(gvk, scope)

				// TODO formalize this by checking to see if they support listing
				versionMapper.Add(version.WithKind(resource.Kind+"List"), scope)
			}

			// we need to add List.  Its a special case of something we need that isn't in the discovery doc
			if group.Name == kapi.GroupName {
				versionMapper.Add(version.WithKind("List"), meta.RESTScopeNamespace)
			}

			unionMapper = append(unionMapper, versionMapper)
		}
	}

	for _, group := range groupPriority {
		resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource})
		kindPriority = append(kindPriority, unversioned.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind})
	}

	return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}, nil
}