1 Star 0 Fork 0

zhuchance / kubernetes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
openapi_cache.go 5.58 KB
一键复制 编辑 原始数据 按行查看 历史
/*
Copyright 2017 The Kubernetes Authors.
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 openapi
import (
"bytes"
"encoding/gob"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/golang/glog"
"k8s.io/client-go/discovery"
"k8s.io/kubernetes/pkg/version"
)
func init() {
registerBinaryEncodingTypes()
}
const openapiFileName = "openapi_cache"
type CachingOpenAPIClient struct {
version string
client discovery.OpenAPISchemaInterface
cacheDirName string
}
// NewCachingOpenAPIClient returns a new discovery.OpenAPISchemaInterface
// that will read the openapi spec from a local cache if it exists, and
// if not will then fetch an openapi spec using a client.
// client: used to fetch a new openapi spec if a local cache is not found
// version: the server version and used as part of the cache file location
// cacheDir: the directory under which the cache file will be written
func NewCachingOpenAPIClient(client discovery.OpenAPISchemaInterface, version, cacheDir string) *CachingOpenAPIClient {
return &CachingOpenAPIClient{
client: client,
version: version,
cacheDirName: cacheDir,
}
}
// OpenAPIData returns an openapi spec.
// It will first attempt to read the spec from a local cache
// If it cannot read a local cache, it will read the file
// using the client and then write the cache.
func (c *CachingOpenAPIClient) OpenAPIData() (*Resources, error) {
// Try to use the cached version
if c.useCache() {
doc, err := c.readOpenAPICache()
if err == nil {
return doc, nil
}
}
// No cached version found, download from server
s, err := c.client.OpenAPISchema()
if err != nil {
glog.V(2).Infof("Failed to download openapi data %v", err)
return nil, err
}
oa, err := NewOpenAPIData(s)
if err != nil {
glog.V(2).Infof("Failed to parse openapi data %v", err)
return nil, err
}
// Try to cache the openapi spec
if c.useCache() {
err = c.writeToCache(oa)
if err != nil {
// Just log an message, no need to fail the command since we got the data we need
glog.V(2).Infof("Unable to cache openapi spec %v", err)
}
}
// Return the parsed data
return oa, nil
}
// useCache returns true if the client should try to use the cache file
func (c *CachingOpenAPIClient) useCache() bool {
return len(c.version) > 0 && len(c.cacheDirName) > 0
}
// readOpenAPICache tries to read the openapi spec from the local file cache
func (c *CachingOpenAPIClient) readOpenAPICache() (*Resources, error) {
// Get the filename to read
filename := c.openAPICacheFilename()
// Read the cached file
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
// Decode the openapi spec
s, err := c.decodeSpec(data)
return s, err
}
// decodeSpec binary decodes the openapi spec
func (c *CachingOpenAPIClient) decodeSpec(data []byte) (*Resources, error) {
b := bytes.NewBuffer(data)
d := gob.NewDecoder(b)
parsed := &Resources{}
err := d.Decode(parsed)
return parsed, err
}
// encodeSpec binary encodes the openapi spec
func (c *CachingOpenAPIClient) encodeSpec(parsed *Resources) ([]byte, error) {
b := &bytes.Buffer{}
e := gob.NewEncoder(b)
err := e.Encode(parsed)
return b.Bytes(), err
}
// writeToCache tries to write the openapi spec to the local file cache.
// writes the data to a new tempfile, and then links the cache file and the tempfile
func (c *CachingOpenAPIClient) writeToCache(parsed *Resources) error {
// Get the constant filename used to read the cache.
cacheFile := c.openAPICacheFilename()
// Binary encode the spec. This is 10x as fast as using json encoding. (60ms vs 600ms)
b, err := c.encodeSpec(parsed)
if err != nil {
return fmt.Errorf("Could not binary encode openapi spec: %v", err)
}
// Create a new temp file for the cached openapi spec.
cacheDir := filepath.Dir(cacheFile)
if err := os.MkdirAll(cacheDir, 0755); err != nil {
return fmt.Errorf("Could not create directory: %v %v", cacheDir, err)
}
tmpFile, err := ioutil.TempFile(cacheDir, "openapi")
if err != nil {
return fmt.Errorf("Could not create temp cache file: %v %v", cacheFile, err)
}
// Write the binary encoded openapi spec to the temp file
if _, err := io.Copy(tmpFile, bytes.NewBuffer(b)); err != nil {
return fmt.Errorf("Could not write temp cache file: %v", err)
}
// Link the temp cache file to the constant cache filepath
return linkFiles(tmpFile.Name(), cacheFile)
}
// openAPICacheFilename returns the filename to read the cache from
func (c *CachingOpenAPIClient) openAPICacheFilename() string {
// Cache using the client and server versions
return filepath.Join(c.cacheDirName, c.version, version.Get().GitVersion, openapiFileName)
}
// linkFiles links the old file to the new file
func linkFiles(old, new string) error {
if err := os.Link(old, new); err != nil {
// If we can't write due to file existing, or permission problems, keep going.
if os.IsExist(err) || os.IsPermission(err) {
return nil
}
return err
}
return nil
}
// registerBinaryEncodingTypes registers the types so they can be binary encoded by gob
func registerBinaryEncodingTypes() {
gob.Register(map[string]interface{}{})
gob.Register([]interface{}{})
gob.Register(Resources{})
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/meoom/kubernetes.git
git@gitee.com:meoom/kubernetes.git
meoom
kubernetes
kubernetes
v1.7.3-beta.0

搜索帮助

344bd9b3 5694891 D2dac590 5694891