Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"time"

openapi_v2 "github.com/googleapis/gnostic/openapiv2"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"
"k8s.io/klog/v2"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -240,6 +241,15 @@ func (d *CachedDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
return d.delegate.OpenAPISchema()
}

// OpenAPISchema retrieves and parses the swagger API schema the server supports.
func (d *CachedDiscoveryClient) OpenAPIV3Schema(path, hash string) (*openapi_v3.Document, error) {
return d.delegate.OpenAPIV3Schema(path, hash)
}

func (d *CachedDiscoveryClient) OpenAPIV3Discovery() (*discovery.OpenAPIV3Discovery, error) {
return d.delegate.OpenAPIV3Discovery()
}

// Fresh is supposed to tell the caller whether or not to retry if the cache
// fails to find something (false = retry, true = no need to retry).
func (d *CachedDiscoveryClient) Fresh() bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"syscall"

openapi_v2 "github.com/googleapis/gnostic/openapiv2"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"

errorsutil "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -149,6 +150,14 @@ func (d *memCacheClient) OpenAPISchema() (*openapi_v2.Document, error) {
return d.delegate.OpenAPISchema()
}

func (d *memCacheClient) OpenAPIV3Schema(path, hash string) (*openapi_v3.Document, error) {
return d.delegate.OpenAPIV3Schema(path, hash)
}

func (d *memCacheClient) OpenAPIV3Discovery() (*discovery.OpenAPIV3Discovery, error) {
return d.delegate.OpenAPIV3Discovery()
}

func (d *memCacheClient) Fresh() bool {
d.lock.RLock()
defer d.lock.RUnlock()
Expand Down
51 changes: 48 additions & 3 deletions staging/src/k8s.io/client-go/discovery/discovery_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
//nolint:staticcheck // SA1019 Keep using module since it's still being maintained and the api of google.golang.org/protobuf/proto differs
"github.com/golang/protobuf/proto"
openapi_v2 "github.com/googleapis/gnostic/openapiv2"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -46,7 +47,9 @@ const (
// defaultRetries is the number of times a resource discovery is repeated if an api group disappears on the fly (e.g. CustomResourceDefinitions).
defaultRetries = 2
// protobuf mime type
mimePb = "application/[email protected]+protobuf"
openAPIV2mimePb = "application/[email protected]+protobuf"

openAPIV3mimePb = "application/[email protected]+protobuf"
// defaultTimeout is the maximum amount of time per request when no timeout has been set on a RESTClient.
// Defaults to 32s in order to have a distinguishable length of time, relative to other timeouts that exist.
defaultTimeout = 32 * time.Second
Expand All @@ -60,6 +63,7 @@ type DiscoveryInterface interface {
ServerResourcesInterface
ServerVersionInterface
OpenAPISchemaInterface
OpenAPIV3SchemaInterface
}

// CachedDiscoveryInterface is a DiscoveryInterface with cache invalidation and freshness.
Expand Down Expand Up @@ -128,6 +132,11 @@ type OpenAPISchemaInterface interface {
OpenAPISchema() (*openapi_v2.Document, error)
}

type OpenAPIV3SchemaInterface interface {
OpenAPIV3Discovery() (*OpenAPIV3Discovery, error)
OpenAPIV3Schema(string, string) (*openapi_v3.Document, error)
}

// DiscoveryClient implements the functions that discover server-supported API groups,
// versions and resources.
type DiscoveryClient struct {
Expand Down Expand Up @@ -420,9 +429,9 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
return &info, nil
}

// OpenAPISchema fetches the open api schema using a rest client and parses the proto.
// OpenAPISchema fetches the open api v2 schema using a rest client and parses the proto.
func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
data, err := d.restClient.Get().AbsPath("/openapi/v2").SetHeader("Accept", mimePb).Do(context.TODO()).Raw()
data, err := d.restClient.Get().AbsPath("/openapi/v2").SetHeader("Accept", openAPIV2mimePb).Do(context.TODO()).Raw()
if err != nil {
if errors.IsForbidden(err) || errors.IsNotFound(err) || errors.IsNotAcceptable(err) {
// single endpoint not found/registered in old server, try to fetch old endpoint
Expand All @@ -443,6 +452,42 @@ func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
return document, nil
}


type OpenAPIV3Discovery struct {
Paths map[string]string
}


func (d *DiscoveryClient) OpenAPIV3Discovery() (*OpenAPIV3Discovery, error) {
data, err := d.restClient.Get().AbsPath("/openapi/v3").Do(context.TODO()).Raw()
if err != nil {
return nil, err
}

foo := &OpenAPIV3Discovery{}
err = json.Unmarshal(data, foo)
if err != nil {
return nil, err
}

return foo, nil
}

func (d *DiscoveryClient) OpenAPIV3Schema(path, hash string) (*openapi_v3.Document, error) {
data, err := d.restClient.Get().AbsPath("/openapi/v3", path).Param("hash", hash).SetHeader("Accept", openAPIV3mimePb).Do(context.TODO()).Raw()
if err != nil {
return nil, err
}
document := &openapi_v3.Document{}
err = proto.Unmarshal(data, document)
if err != nil {
return nil, err
}

return document, nil
}


// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
func withRetries(maxRetries int, f func() ([]*metav1.APIGroup, []*metav1.APIResourceList, error)) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
var result []*metav1.APIResourceList
Expand Down
11 changes: 11 additions & 0 deletions staging/src/k8s.io/client-go/discovery/fake/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"net/http"

openapi_v2 "github.com/googleapis/gnostic/openapiv2"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand All @@ -29,6 +30,8 @@ import (
kubeversion "k8s.io/client-go/pkg/version"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/testing"

"k8s.io/client-go/discovery"
)

// FakeDiscovery implements discovery.DiscoveryInterface and sometimes calls testing.Fake.Invoke with an action,
Expand Down Expand Up @@ -161,6 +164,14 @@ func (c *FakeDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
return &openapi_v2.Document{}, nil
}

func (d *FakeDiscovery) OpenAPIV3Schema(path, hash string) (*openapi_v3.Document, error) {
return &openapi_v3.Document{}, nil
}

func (d *FakeDiscovery) OpenAPIV3Discovery() (*discovery.OpenAPIV3Discovery, error) {
return nil, nil
}

// RESTClient returns a RESTClient that is used to communicate with API server
// by this client implementation.
func (c *FakeDiscovery) RESTClient() restclient.Interface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (s *Downloader) handlerWithUser(handler http.Handler, info user.Info) http.

// gvList is a struct for the response of the /openapi/v3 endpoint to unmarshal into
type gvList struct {
Paths []string `json:"Paths"`
Paths map[string]string `json:"Paths"`
}

// SpecETag is a OpenAPI v3 spec and etag pair for the endpoint of each OpenAPI group/version
Expand Down Expand Up @@ -81,7 +81,7 @@ func (s *Downloader) Download(handler http.Handler, etagList map[string]string)
if err := json.Unmarshal(writer.data, &groups); err != nil {
return nil, err
}
for _, path := range groups.Paths {
for path, _ := range groups.Paths {
reqPath := fmt.Sprintf("/openapi/v3/%s", path)
req, err := http.NewRequest("GET", reqPath, nil)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/explain/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func (o *ExplainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil {
return err
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/util/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/util/openapi"
"k8s.io/kubectl/pkg/validation"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"
)

// Factory provides abstractions that allow the Kubectl command to be extended across multiple types
Expand Down Expand Up @@ -66,4 +67,10 @@ type Factory interface {
OpenAPISchema() (openapi.Resources, error)
// OpenAPIGetter returns a getter for the openapi schema document
OpenAPIGetter() discovery.OpenAPISchemaInterface

// OpenAPIV3Discovery returns the list of paths for OpenAPI V3 documents
OpenAPIV3Discovery() (*discovery.OpenAPIV3Discovery, error)

// OpenAPIV3GroupVersionSchema returns the OpenAPI V3 schema for the corresponding group version
OpenAPIV3GroupVersionSchema(path, hash string) (*openapi_v3.Document, error)
}
21 changes: 21 additions & 0 deletions staging/src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"k8s.io/kubectl/pkg/util/openapi"
openapivalidation "k8s.io/kubectl/pkg/util/openapi/validation"
"k8s.io/kubectl/pkg/validation"
openapi_v3 "github.com/googleapis/gnostic/openapiv3"
)

type factoryImpl struct {
Expand Down Expand Up @@ -186,3 +187,23 @@ func (f *factoryImpl) OpenAPIGetter() discovery.OpenAPISchemaInterface {

return f.openAPIGetter
}

func (f *factoryImpl) OpenAPIV3Discovery() (*discovery.OpenAPIV3Discovery, error) {
discovery, err := f.clientGetter.ToDiscoveryClient()
if err != nil {
return nil, err
}

foo, err := discovery.OpenAPIV3Discovery()
return foo, err
}

func (f *factoryImpl) OpenAPIV3GroupVersionSchema(path, hash string) (*openapi_v3.Document, error) {
discovery, err := f.clientGetter.ToDiscoveryClient()
if err != nil {
return nil, err
}

schema, err := discovery.OpenAPIV3Schema(path, hash)
return schema, err
}
37 changes: 32 additions & 5 deletions vendor/k8s.io/kube-openapi/pkg/handler3/handler.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.