...
1
16
17 package openapi3
18
19 import (
20 "encoding/json"
21 "fmt"
22 "sort"
23 "strings"
24
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 "k8s.io/client-go/openapi"
28 "k8s.io/kube-openapi/pkg/spec3"
29 )
30
31
32
33
34
35
36
37
38
39
40 type Root interface {
41
42
43
44 GroupVersions() ([]schema.GroupVersion, error)
45
46
47
48
49 GVSpec(gv schema.GroupVersion) (*spec3.OpenAPI, error)
50
51
52
53
54 GVSpecAsMap(gv schema.GroupVersion) (map[string]interface{}, error)
55 }
56
57
58
59 type root struct {
60
61 client openapi.Client
62 }
63
64
65 var _ Root = &root{}
66
67
68
69 func NewRoot(client openapi.Client) Root {
70 return &root{client: client}
71 }
72
73 func (r *root) GroupVersions() ([]schema.GroupVersion, error) {
74 paths, err := r.client.Paths()
75 if err != nil {
76 return nil, err
77 }
78
79 gvs := make([]schema.GroupVersion, 0, len(paths))
80 for gvAPIPath := range paths {
81 gv, err := pathToGroupVersion(gvAPIPath)
82 if err != nil {
83
84 continue
85 }
86 gvs = append(gvs, gv)
87 }
88
89 sort.Slice(gvs, func(i, j int) bool {
90 return gvs[i].String() < gvs[j].String()
91 })
92 return gvs, nil
93 }
94
95 func (r *root) GVSpec(gv schema.GroupVersion) (*spec3.OpenAPI, error) {
96 openAPISchemaBytes, err := r.retrieveGVBytes(gv)
97 if err != nil {
98 return nil, err
99 }
100
101 var parsedV3Schema spec3.OpenAPI
102 err = json.Unmarshal(openAPISchemaBytes, &parsedV3Schema)
103 return &parsedV3Schema, err
104 }
105
106 func (r *root) GVSpecAsMap(gv schema.GroupVersion) (map[string]interface{}, error) {
107 gvOpenAPIBytes, err := r.retrieveGVBytes(gv)
108 if err != nil {
109 return nil, err
110 }
111
112 var gvMap map[string]interface{}
113 err = json.Unmarshal(gvOpenAPIBytes, &gvMap)
114 return gvMap, err
115 }
116
117
118
119
120 func (r *root) retrieveGVBytes(gv schema.GroupVersion) ([]byte, error) {
121 paths, err := r.client.Paths()
122 if err != nil {
123 return nil, err
124 }
125 apiPath := gvToAPIPath(gv)
126 gvOpenAPI, found := paths[apiPath]
127 if !found {
128 return nil, &GroupVersionNotFoundError{gv: gv}
129 }
130 return gvOpenAPI.Schema(runtime.ContentTypeJSON)
131 }
132
133
134
135
136
137 func gvToAPIPath(gv schema.GroupVersion) string {
138 var resourcePath string
139 if len(gv.Group) == 0 {
140 resourcePath = fmt.Sprintf("api/%s", gv.Version)
141 } else {
142 resourcePath = fmt.Sprintf("apis/%s/%s", gv.Group, gv.Version)
143 }
144 return resourcePath
145 }
146
147
148
149
150
151
152 func pathToGroupVersion(path string) (schema.GroupVersion, error) {
153 var gv schema.GroupVersion
154 parts := strings.Split(path, "/")
155 if len(parts) < 2 {
156 return gv, fmt.Errorf("Unable to parse api relative path: %s", path)
157 }
158 apiPrefix := parts[0]
159 if apiPrefix == "apis" {
160
161 if len(parts) < 3 {
162 return gv, fmt.Errorf("Group without Version not allowed")
163 }
164 gv.Group = parts[1]
165 gv.Version = parts[2]
166 } else if apiPrefix == "api" {
167 gv.Version = parts[1]
168 } else {
169 return gv, fmt.Errorf("Unable to parse api relative path: %s", path)
170 }
171 return gv, nil
172 }
173
174
175
176 type GroupVersionNotFoundError struct {
177 gv schema.GroupVersion
178 }
179
180 func (r *GroupVersionNotFoundError) Error() string {
181 return fmt.Sprintf("GroupVersion (%v) not found as OpenAPI V3 path", r.gv)
182 }
183
View as plain text