forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcached_discovery.go
136 lines (113 loc) · 4.35 KB
/
cached_discovery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package clientcmd
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"time"
"github.com/golang/glog"
kapi "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/client/typed/discovery"
"k8s.io/kubernetes/pkg/runtime"
)
// CachedDiscoveryClient implements the functions that discovery server-supported API groups,
// versions and resources.
type CachedDiscoveryClient struct {
discovery.DiscoveryInterface
// cacheDirectory is the directory where discovery docs are held. It must be unique per host:port combination to work well.
cacheDirectory string
// ttl is how long the cache should be considered valid
ttl time.Duration
}
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
func (d *CachedDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error) {
filename := filepath.Join(d.cacheDirectory, groupVersion, "serverresources.json")
cachedBytes, err := d.getCachedFile(filename)
// don't fail on errors, we either don't have a file or won't be able to run the cached check. Either way we can fallback.
if err == nil {
cachedResources := &unversioned.APIResourceList{}
if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), cachedBytes, cachedResources); err == nil {
glog.V(6).Infof("returning cached discovery info from %v", filename)
return cachedResources, nil
}
}
liveResources, err := d.DiscoveryInterface.ServerResourcesForGroupVersion(groupVersion)
if err != nil {
return liveResources, err
}
if err := d.writeCachedFile(filename, liveResources); err != nil {
glog.V(3).Infof("failed to write cache to %v due to %v", filename, err)
}
return liveResources, nil
}
// ServerResources returns the supported resources for all groups and versions.
func (d *CachedDiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) {
apiGroups, err := d.ServerGroups()
if err != nil {
return nil, err
}
groupVersions := unversioned.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 (d *CachedDiscoveryClient) ServerGroups() (*unversioned.APIGroupList, error) {
filename := filepath.Join(d.cacheDirectory, "servergroups.json")
cachedBytes, err := d.getCachedFile(filename)
// don't fail on errors, we either don't have a file or won't be able to run the cached check. Either way we can fallback.
if err == nil {
cachedGroups := &unversioned.APIGroupList{}
if err := runtime.DecodeInto(kapi.Codecs.UniversalDecoder(), cachedBytes, cachedGroups); err == nil {
glog.V(6).Infof("returning cached discovery info from %v", filename)
return cachedGroups, nil
}
}
liveGroups, err := d.DiscoveryInterface.ServerGroups()
if err != nil {
return liveGroups, err
}
if err := d.writeCachedFile(filename, liveGroups); err != nil {
glog.V(3).Infof("failed to write cache to %v due to %v", filename, err)
}
return liveGroups, nil
}
func (d *CachedDiscoveryClient) getCachedFile(filename string) ([]byte, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
fileInfo, err := file.Stat()
if err != nil {
return nil, err
}
if time.Now().After(fileInfo.ModTime().Add(d.ttl)) {
return nil, errors.New("cache expired")
}
// the cache is present and its valid. Try to read and use it.
cachedBytes, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
return cachedBytes, nil
}
func (d *CachedDiscoveryClient) writeCachedFile(filename string, obj runtime.Object) error {
if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
return err
}
bytes, err := runtime.Encode(kapi.Codecs.LegacyCodec(), obj)
if err != nil {
return err
}
return ioutil.WriteFile(filename, bytes, 0755)
}
// NewCachedDiscoveryClient creates a new DiscoveryClient. cacheDirectory is the directory where discovery docs are held. It must be unique per host:port combination to work well.
func NewCachedDiscoveryClient(delegate discovery.DiscoveryInterface, cacheDirectory string, ttl time.Duration) *CachedDiscoveryClient {
return &CachedDiscoveryClient{DiscoveryInterface: delegate, cacheDirectory: cacheDirectory, ttl: ttl}
}