mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
add discovery client
This commit is contained in:
parent
c9d6037c81
commit
5859da3e1f
@ -292,7 +292,7 @@ func (s *CMServer) Run(_ []string) error {
|
|||||||
}
|
}
|
||||||
versions := &unversioned.APIVersions{Versions: versionStrings}
|
versions := &unversioned.APIVersions{Versions: versionStrings}
|
||||||
|
|
||||||
resourceMap, err := client.SupportedResources(kubeClient, kubeconfig)
|
resourceMap, err := kubeClient.Discovery().ServerResources()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Fatalf("Failed to get supported resources from server: %v", err)
|
glog.Fatalf("Failed to get supported resources from server: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ type Interface interface {
|
|||||||
ComponentStatusesInterface
|
ComponentStatusesInterface
|
||||||
SwaggerSchemaInterface
|
SwaggerSchemaInterface
|
||||||
Extensions() ExtensionsInterface
|
Extensions() ExtensionsInterface
|
||||||
ResourcesInterface
|
Discovery() DiscoveryInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
||||||
@ -120,11 +120,6 @@ type VersionInterface interface {
|
|||||||
ServerAPIVersions() (*unversioned.APIVersions, error)
|
ServerAPIVersions() (*unversioned.APIVersions, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourcesInterface has methods for obtaining supported resources on the API server
|
|
||||||
type ResourcesInterface interface {
|
|
||||||
SupportedResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIStatus is exposed by errors that can be converted to an api.Status object
|
// APIStatus is exposed by errors that can be converted to an api.Status object
|
||||||
// for finer grained details.
|
// for finer grained details.
|
||||||
type APIStatus interface {
|
type APIStatus interface {
|
||||||
@ -135,6 +130,8 @@ type APIStatus interface {
|
|||||||
type Client struct {
|
type Client struct {
|
||||||
*RESTClient
|
*RESTClient
|
||||||
*ExtensionsClient
|
*ExtensionsClient
|
||||||
|
// TODO: remove this when we re-structure pkg/client.
|
||||||
|
*DiscoveryClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerVersion retrieves and parses the server's version.
|
// ServerVersion retrieves and parses the server's version.
|
||||||
@ -151,42 +148,6 @@ func (c *Client) ServerVersion() (*version.Info, error) {
|
|||||||
return &info, nil
|
return &info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SupportedResourcesForGroupVersion retrieves the list of resources supported by the API server for a group version.
|
|
||||||
func (c *Client) SupportedResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) {
|
|
||||||
var prefix string
|
|
||||||
if groupVersion == "v1" {
|
|
||||||
prefix = "/api"
|
|
||||||
} else {
|
|
||||||
prefix = "/apis"
|
|
||||||
}
|
|
||||||
body, err := c.Get().AbsPath(prefix, groupVersion).Do().Raw()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resources := unversioned.APIResourceList{}
|
|
||||||
if err := json.Unmarshal(body, &resources); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resources, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SupportedResources gets all supported resources for all group versions. The key in the map is an API groupVersion.
|
|
||||||
func SupportedResources(c Interface, cfg *Config) (map[string]*unversioned.APIResourceList, error) {
|
|
||||||
apis, err := ServerAPIVersions(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := map[string]*unversioned.APIResourceList{}
|
|
||||||
for _, groupVersion := range apis {
|
|
||||||
resources, err := c.SupportedResourcesForGroupVersion(groupVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result[groupVersion] = resources
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServerAPIVersions retrieves and parses the list of API versions the server supports.
|
// ServerAPIVersions retrieves and parses the list of API versions the server supports.
|
||||||
func (c *Client) ServerAPIVersions() (*unversioned.APIVersions, error) {
|
func (c *Client) ServerAPIVersions() (*unversioned.APIVersions, error) {
|
||||||
body, err := c.Get().UnversionedPath("").Do().Raw()
|
body, err := c.Get().UnversionedPath("").Do().Raw()
|
||||||
@ -288,3 +249,7 @@ func IsTimeout(err error) bool {
|
|||||||
func (c *Client) Extensions() ExtensionsInterface {
|
func (c *Client) Extensions() ExtensionsInterface {
|
||||||
return c.ExtensionsClient
|
return c.ExtensionsClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Discovery() DiscoveryInterface {
|
||||||
|
return c.DiscoveryClient
|
||||||
|
}
|
||||||
|
@ -352,7 +352,7 @@ func TestGetServerResources(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
client := NewOrDie(&Config{Host: server.URL})
|
client := NewOrDie(&Config{Host: server.URL})
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
got, err := client.SupportedResourcesForGroupVersion(test.request)
|
got, err := client.Discovery().ServerResourcesForGroupVersion(test.request)
|
||||||
if test.expectErr {
|
if test.expectErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("unexpected non-error")
|
t.Error("unexpected non-error")
|
||||||
@ -368,7 +368,7 @@ func TestGetServerResources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceMap, err := SupportedResources(client, &Config{Host: server.URL})
|
resourceMap, err := client.Discovery().ServerResources()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
175
pkg/client/unversioned/discovery_client.go
Normal file
175
pkg/client/unversioned/discovery_client.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package unversioned
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DiscoveryInterface holds the methods that discover server-supported API groups,
|
||||||
|
// versions and resources.
|
||||||
|
type DiscoveryInterface interface {
|
||||||
|
ServerGroupsInterface
|
||||||
|
ServerResourcesInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupsInterface has methods for obtaining supported groups on the API server
|
||||||
|
type ServerGroupsInterface interface {
|
||||||
|
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||||
|
// preferred version.
|
||||||
|
ServerGroups() (*unversioned.APIGroupList, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerResourcesInterface has methods for obtaining supported resources on the API server
|
||||||
|
type ServerResourcesInterface interface {
|
||||||
|
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||||
|
ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error)
|
||||||
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
ServerResources() (map[string]*unversioned.APIResourceList, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoveryClient implements the functions that dicovery server-supported API groups,
|
||||||
|
// versions and resources.
|
||||||
|
type DiscoveryClient struct {
|
||||||
|
httpClient HTTPClient
|
||||||
|
baseURL url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so
|
||||||
|
// group would be "".
|
||||||
|
func apiVersionsToAPIGroup(apiVersions *unversioned.APIVersions) (apiGroup unversioned.APIGroup) {
|
||||||
|
groupVersions := []unversioned.GroupVersion{}
|
||||||
|
for _, version := range apiVersions.Versions {
|
||||||
|
groupVersion := unversioned.GroupVersion{
|
||||||
|
GroupVersion: version,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
groupVersions = append(groupVersions, groupVersion)
|
||||||
|
}
|
||||||
|
apiGroup.Versions = groupVersions
|
||||||
|
// There should be only one groupVersion returned at /api
|
||||||
|
apiGroup.PreferredVersion = groupVersions[0]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DiscoveryClient) get(url string) (resp *http.Response, err error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return d.httpClient.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIGroups returns the supported groups, with information like supported versions and the
|
||||||
|
// preferred version.
|
||||||
|
func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList, err error) {
|
||||||
|
// Get the groupVersions exposed at /api
|
||||||
|
url := d.baseURL
|
||||||
|
url.Path = "/api"
|
||||||
|
resp, err := d.get(url.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var v unversioned.APIVersions
|
||||||
|
defer resp.Body.Close()
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
apiGroup := apiVersionsToAPIGroup(&v)
|
||||||
|
|
||||||
|
// Get the groupVersions exposed at /apis
|
||||||
|
url.Path = "/apis"
|
||||||
|
resp2, err := d.get(url.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp2.Body.Close()
|
||||||
|
apiGroupList = &unversioned.APIGroupList{}
|
||||||
|
if err = json.NewDecoder(resp2.Body).Decode(&apiGroupList); err != nil {
|
||||||
|
return nil, fmt.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the group retrieved from /api to the list
|
||||||
|
apiGroupList.Groups = append(apiGroupList.Groups, apiGroup)
|
||||||
|
return apiGroupList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIResourcesForGroup returns the supported resources for a group and version.
|
||||||
|
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.APIResourceList, err error) {
|
||||||
|
url := d.baseURL
|
||||||
|
if groupVersion == "v1" {
|
||||||
|
url.Path = "/api/" + groupVersion
|
||||||
|
} else {
|
||||||
|
url.Path = "/apis/" + groupVersion
|
||||||
|
}
|
||||||
|
resp, err := d.get(url.String())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
resources = &unversioned.APIResourceList{}
|
||||||
|
if err = json.NewDecoder(resp.Body).Decode(resources); err != nil {
|
||||||
|
return nil, fmt.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
return resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIResources returns the supported resources for all groups and versions.
|
||||||
|
func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) {
|
||||||
|
apiGroups, err := d.ServerGroups()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
groupVersions := extractGroupVersions(apiGroups)
|
||||||
|
result := map[string]*unversioned.APIResourceList{}
|
||||||
|
for _, groupVersion := range groupVersions {
|
||||||
|
resources, err := d.ServerResourcesForGroupVersion(groupVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
result[groupVersion] = resources
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDiscoveryDefaults(config *Config) error {
|
||||||
|
config.Prefix = ""
|
||||||
|
config.Version = ""
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDiscoveryClient creates a new DiscoveryClient for the given config. This client
|
||||||
|
// can be used to discover supported resources in the API server.
|
||||||
|
func NewDiscoveryClient(c *Config) (*DiscoveryClient, error) {
|
||||||
|
config := *c
|
||||||
|
if err := setDiscoveryDefaults(&config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport, err := TransportFor(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
client := &http.Client{Transport: transport}
|
||||||
|
baseURL, err := defaultServerUrlFor(c)
|
||||||
|
return &DiscoveryClient{client, *baseURL}, nil
|
||||||
|
}
|
@ -146,15 +146,22 @@ func New(c *Config) (*Client, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
discoveryConfig := *c
|
||||||
|
discoveryClient, err := NewDiscoveryClient(&discoveryConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := latest.Group("extensions"); err != nil {
|
if _, err := latest.Group("extensions"); err != nil {
|
||||||
return &Client{RESTClient: client, ExtensionsClient: nil}, nil
|
return &Client{RESTClient: client, ExtensionsClient: nil, DiscoveryClient: discoveryClient}, nil
|
||||||
}
|
}
|
||||||
experimentalConfig := *c
|
experimentalConfig := *c
|
||||||
experimentalClient, err := NewExtensions(&experimentalConfig)
|
experimentalClient, err := NewExtensions(&experimentalConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Client{RESTClient: client, ExtensionsClient: experimentalClient}, nil
|
|
||||||
|
return &Client{RESTClient: client, ExtensionsClient: experimentalClient, DiscoveryClient: discoveryClient}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatchesServerVersion queries the server to compares the build version
|
// MatchesServerVersion queries the server to compares the build version
|
||||||
|
@ -61,7 +61,7 @@ type Fake struct {
|
|||||||
// ProxyReactionChain is the list of proxy reactors that will be attempted for every request in the order they are tried
|
// ProxyReactionChain is the list of proxy reactors that will be attempted for every request in the order they are tried
|
||||||
ProxyReactionChain []ProxyReactor
|
ProxyReactionChain []ProxyReactor
|
||||||
|
|
||||||
Resources []unversioned.APIResourceList
|
Resources map[string]*unversioned.APIResourceList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reactor is an interface to allow the composition of reaction functions.
|
// Reactor is an interface to allow the composition of reaction functions.
|
||||||
@ -274,18 +274,8 @@ func (c *Fake) Extensions() client.ExtensionsInterface {
|
|||||||
return &FakeExperimental{c}
|
return &FakeExperimental{c}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Fake) SupportedResourcesForGroupVersion(version string) (*unversioned.APIResourceList, error) {
|
func (c *Fake) Discovery() client.DiscoveryInterface {
|
||||||
action := ActionImpl{
|
return &FakeDiscovery{c}
|
||||||
Verb: "get",
|
|
||||||
Resource: "resource",
|
|
||||||
}
|
|
||||||
c.Invokes(action, nil)
|
|
||||||
for _, resource := range c.Resources {
|
|
||||||
if resource.GroupVersion == version {
|
|
||||||
return &resource, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Fake) ServerVersion() (*version.Info, error) {
|
func (c *Fake) ServerVersion() (*version.Info, error) {
|
||||||
@ -348,3 +338,29 @@ func (c *FakeExperimental) Jobs(namespace string) client.JobInterface {
|
|||||||
func (c *FakeExperimental) Ingress(namespace string) client.IngressInterface {
|
func (c *FakeExperimental) Ingress(namespace string) client.IngressInterface {
|
||||||
return &FakeIngress{Fake: c, Namespace: namespace}
|
return &FakeIngress{Fake: c, Namespace: namespace}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FakeDiscovery struct {
|
||||||
|
*Fake
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) {
|
||||||
|
action := ActionImpl{
|
||||||
|
Verb: "get",
|
||||||
|
Resource: "resource",
|
||||||
|
}
|
||||||
|
c.Invokes(action, nil)
|
||||||
|
return c.Resources[groupVersion], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDiscovery) ServerResources() (map[string]*unversioned.APIResourceList, error) {
|
||||||
|
action := ActionImpl{
|
||||||
|
Verb: "get",
|
||||||
|
Resource: "resource",
|
||||||
|
}
|
||||||
|
c.Invokes(action, nil)
|
||||||
|
return c.Resources, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeDiscovery) ServerGroups() (*unversioned.APIGroupList, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -194,7 +194,7 @@ func deleteAllContent(kubeClient client.Interface, versions *unversioned.APIVers
|
|||||||
}
|
}
|
||||||
// If experimental mode, delete all experimental resources for the namespace.
|
// If experimental mode, delete all experimental resources for the namespace.
|
||||||
if containsVersion(versions, "extensions/v1beta1") {
|
if containsVersion(versions, "extensions/v1beta1") {
|
||||||
resources, err := kubeClient.SupportedResourcesForGroupVersion("extensions/v1beta1")
|
resources, err := kubeClient.Discovery().ServerResourcesForGroupVersion("extensions/v1beta1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return estimate, err
|
return estimate, err
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *unversioned.APIV
|
|||||||
for _, resource := range []string{"daemonsets", "deployments", "jobs", "horizontalpodautoscalers", "ingress"} {
|
for _, resource := range []string{"daemonsets", "deployments", "jobs", "horizontalpodautoscalers", "ingress"} {
|
||||||
resources = append(resources, unversioned.APIResource{Name: resource})
|
resources = append(resources, unversioned.APIResource{Name: resource})
|
||||||
}
|
}
|
||||||
mockClient.Resources = []unversioned.APIResourceList{
|
mockClient.Resources = map[string]*unversioned.APIResourceList{
|
||||||
{
|
"extensions/v1beta1": {
|
||||||
GroupVersion: "extensions/v1beta1",
|
GroupVersion: "extensions/v1beta1",
|
||||||
APIResources: resources,
|
APIResources: resources,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user