mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Add HasOpenAPISchemaChanged to DiscoveryInterface
This commit is contained in:
parent
7b9757faa4
commit
235a57a29e
@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@ -32,40 +30,25 @@ type objectTypeCache interface {
|
||||
type nonCachingObjectTypeCache struct {
|
||||
// TODO: lock this?
|
||||
discoveryClient discovery.DiscoveryInterface
|
||||
docHash [sha512.Size]uint8
|
||||
gvkParser *fieldmanager.GvkParser
|
||||
typeForGVK map[schema.GroupVersionKind]*typed.ParseableType
|
||||
}
|
||||
|
||||
// objectTypeForGVK retrieves the typed.ParseableType for a given gvk from the cache
|
||||
func (c *nonCachingObjectTypeCache) objectTypeForGVK(gvk schema.GroupVersionKind) (*typed.ParseableType, error) {
|
||||
doc, err := c.discoveryClient.OpenAPISchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
docBytes, err := json.Marshal(doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
docHash := sha512.Sum512(docBytes)
|
||||
|
||||
// cache hit
|
||||
if c.docHash == docHash {
|
||||
if !c.discoveryClient.HasOpenAPISchemaChanged() && c.gvkParser != nil {
|
||||
// cache hit
|
||||
fmt.Println("cache hit")
|
||||
fmt.Printf("docHash = %+v\n", docHash)
|
||||
objType, ok := c.typeForGVK[gvk]
|
||||
if ok {
|
||||
fmt.Println("gvk recognized")
|
||||
fmt.Printf("gvk = %+v\n", gvk)
|
||||
return objType, nil
|
||||
}
|
||||
objType = c.gvkParser.Type(gvk)
|
||||
c.typeForGVK[gvk] = objType
|
||||
return objType, nil
|
||||
fmt.Printf("gvk = %+v\n", gvk)
|
||||
return c.gvkParser.Type(gvk), nil
|
||||
} else {
|
||||
fmt.Println("cache miss")
|
||||
// cache miss
|
||||
fmt.Println("cache miss")
|
||||
fmt.Printf("gvk = %+v\n", gvk)
|
||||
doc, err := c.discoveryClient.OpenAPISchema()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
models, err := proto.NewOpenAPIData(doc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -77,11 +60,7 @@ func (c *nonCachingObjectTypeCache) objectTypeForGVK(gvk schema.GroupVersionKind
|
||||
}
|
||||
|
||||
objType := gvkParser.Type(gvk)
|
||||
c.docHash = docHash
|
||||
c.gvkParser = gvkParser
|
||||
c.typeForGVK = map[schema.GroupVersionKind]*typed.ParseableType{
|
||||
gvk: objType,
|
||||
}
|
||||
|
||||
return objType, nil
|
||||
}
|
||||
|
@ -240,6 +240,10 @@ func (d *CachedDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return d.delegate.OpenAPISchema()
|
||||
}
|
||||
|
||||
func (d *CachedDiscoveryClient) HasOpenAPISchemaChanged() bool {
|
||||
return d.delegate.HasOpenAPISchemaChanged()
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -125,6 +126,8 @@ type ServerVersionInterface interface {
|
||||
type OpenAPISchemaInterface interface {
|
||||
// OpenAPISchema retrieves and parses the swagger API schema the server supports.
|
||||
OpenAPISchema() (*openapi_v2.Document, error)
|
||||
|
||||
HasOpenAPISchemaChanged() bool
|
||||
}
|
||||
|
||||
// DiscoveryClient implements the functions that discover server-supported API groups,
|
||||
@ -133,6 +136,7 @@ type DiscoveryClient struct {
|
||||
restClient restclient.Interface
|
||||
|
||||
LegacyPrefix string
|
||||
etag string
|
||||
}
|
||||
|
||||
// Convert metav1.APIVersions to metav1.APIGroup. APIVersions is used by legacy v1, so
|
||||
@ -419,9 +423,21 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func (d *DiscoveryClient) HasOpenAPISchemaChanged() bool {
|
||||
result := d.restClient.Verb("HEAD").AbsPath("/openapi/v2").SetHeader("If-None-Match", d.etag).SetHeader("Accept", mimePb).Do(context.TODO())
|
||||
var status int
|
||||
result.StatusCode(&status)
|
||||
if status == http.StatusNotModified {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// OpenAPISchema fetches the open api 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()
|
||||
result := d.restClient.Get().AbsPath("/openapi/v2").SetHeader("Accept", mimePb).Do(context.TODO())
|
||||
d.etag = result.Etag()
|
||||
data, err := result.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
|
||||
|
@ -1062,6 +1062,12 @@ func (r *Request) DoRaw(ctx context.Context) ([]byte, error) {
|
||||
|
||||
// transformResponse converts an API response into a structured API object
|
||||
func (r *Request) transformResponse(resp *http.Response, req *http.Request) Result {
|
||||
var etag string
|
||||
etagHeader, ok := resp.Header["Etag"]
|
||||
if ok && len(etagHeader) == 1 {
|
||||
etag = etagHeader[0]
|
||||
}
|
||||
|
||||
var body []byte
|
||||
if resp.Body != nil {
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
@ -1146,6 +1152,7 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request) Resu
|
||||
statusCode: resp.StatusCode,
|
||||
decoder: decoder,
|
||||
warnings: handleWarnings(resp.Header, r.warningHandler),
|
||||
etag: etag,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1272,6 +1279,7 @@ type Result struct {
|
||||
contentType string
|
||||
err error
|
||||
statusCode int
|
||||
etag string
|
||||
|
||||
decoder runtime.Decoder
|
||||
}
|
||||
@ -1308,6 +1316,10 @@ func (r Result) Get() (runtime.Object, error) {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (r Result) Etag() string {
|
||||
return r.etag
|
||||
}
|
||||
|
||||
// StatusCode returns the HTTP status code of the request. (Only valid if no
|
||||
// error was returned.)
|
||||
func (r Result) StatusCode(statusCode *int) Result {
|
||||
|
Loading…
Reference in New Issue
Block a user