mirror of https://github.com/k3s-io/k3s
Merge pull request #15659 from caesarxuchao/discovery-client
Auto commit by PR queue botpull/6/head
commit
68717ddae0
|
@ -293,7 +293,7 @@ func (s *CMServer) Run(_ []string) error {
|
|||
}
|
||||
versions := &unversioned.APIVersions{Versions: versionStrings}
|
||||
|
||||
resourceMap, err := client.SupportedResources(kubeClient, kubeconfig)
|
||||
resourceMap, err := kubeClient.Discovery().ServerResources()
|
||||
if err != nil {
|
||||
glog.Fatalf("Failed to get supported resources from server: %v", err)
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ type Interface interface {
|
|||
ComponentStatusesInterface
|
||||
SwaggerSchemaInterface
|
||||
Extensions() ExtensionsInterface
|
||||
ResourcesInterface
|
||||
Discovery() DiscoveryInterface
|
||||
}
|
||||
|
||||
func (c *Client) ReplicationControllers(namespace string) ReplicationControllerInterface {
|
||||
|
@ -120,11 +120,6 @@ type VersionInterface interface {
|
|||
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
|
||||
// for finer grained details.
|
||||
type APIStatus interface {
|
||||
|
@ -135,6 +130,8 @@ type APIStatus interface {
|
|||
type Client struct {
|
||||
*RESTClient
|
||||
*ExtensionsClient
|
||||
// TODO: remove this when we re-structure pkg/client.
|
||||
*DiscoveryClient
|
||||
}
|
||||
|
||||
// ServerVersion retrieves and parses the server's version.
|
||||
|
@ -151,42 +148,6 @@ func (c *Client) ServerVersion() (*version.Info, error) {
|
|||
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.
|
||||
func (c *Client) ServerAPIVersions() (*unversioned.APIVersions, error) {
|
||||
body, err := c.Get().UnversionedPath("").Do().Raw()
|
||||
|
@ -288,3 +249,7 @@ func IsTimeout(err error) bool {
|
|||
func (c *Client) Extensions() ExtensionsInterface {
|
||||
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})
|
||||
for _, test := range tests {
|
||||
got, err := client.SupportedResourcesForGroupVersion(test.request)
|
||||
got, err := client.Discovery().ServerResourcesForGroupVersion(test.request)
|
||||
if test.expectErr {
|
||||
if err == nil {
|
||||
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 {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
discoveryConfig := *c
|
||||
discoveryClient, err := NewDiscoveryClient(&discoveryConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
experimentalClient, err := NewExtensions(&experimentalConfig)
|
||||
if err != nil {
|
||||
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
|
||||
|
|
|
@ -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 []ProxyReactor
|
||||
|
||||
Resources []unversioned.APIResourceList
|
||||
Resources map[string]*unversioned.APIResourceList
|
||||
}
|
||||
|
||||
// Reactor is an interface to allow the composition of reaction functions.
|
||||
|
@ -274,18 +274,8 @@ func (c *Fake) Extensions() client.ExtensionsInterface {
|
|||
return &FakeExperimental{c}
|
||||
}
|
||||
|
||||
func (c *Fake) SupportedResourcesForGroupVersion(version string) (*unversioned.APIResourceList, error) {
|
||||
action := ActionImpl{
|
||||
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) Discovery() client.DiscoveryInterface {
|
||||
return &FakeDiscovery{c}
|
||||
}
|
||||
|
||||
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 {
|
||||
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 containsVersion(versions, "extensions/v1beta1") {
|
||||
resources, err := kubeClient.SupportedResourcesForGroupVersion("extensions/v1beta1")
|
||||
resources, err := kubeClient.Discovery().ServerResourcesForGroupVersion("extensions/v1beta1")
|
||||
if err != nil {
|
||||
return estimate, err
|
||||
}
|
||||
|
|
|
@ -95,8 +95,8 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, versions *unversioned.APIV
|
|||
for _, resource := range []string{"daemonsets", "deployments", "jobs", "horizontalpodautoscalers", "ingress"} {
|
||||
resources = append(resources, unversioned.APIResource{Name: resource})
|
||||
}
|
||||
mockClient.Resources = []unversioned.APIResourceList{
|
||||
{
|
||||
mockClient.Resources = map[string]*unversioned.APIResourceList{
|
||||
"extensions/v1beta1": {
|
||||
GroupVersion: "extensions/v1beta1",
|
||||
APIResources: resources,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue