...
1
16
17 package openapi
18
19 import (
20 openapi_v2 "github.com/google/gnostic-models/openapiv2"
21
22 "k8s.io/apimachinery/pkg/runtime/schema"
23 "k8s.io/kube-openapi/pkg/util/proto"
24 "sigs.k8s.io/yaml"
25 )
26
27
28
29
30 type OpenAPIResourcesGetter interface {
31 OpenAPISchema() (Resources, error)
32 }
33
34
35
36 type Resources interface {
37 LookupResource(gvk schema.GroupVersionKind) proto.Schema
38 GetConsumes(gvk schema.GroupVersionKind, operation string) []string
39 }
40
41
42
43
44 const groupVersionKindExtensionKey = "x-kubernetes-group-version-kind"
45
46
47
48 type document struct {
49
50 resources map[schema.GroupVersionKind]string
51 models proto.Models
52 doc *openapi_v2.Document
53 }
54
55 var _ Resources = &document{}
56
57
58 func NewOpenAPIData(doc *openapi_v2.Document) (Resources, error) {
59 models, err := proto.NewOpenAPIData(doc)
60 if err != nil {
61 return nil, err
62 }
63
64 resources := map[schema.GroupVersionKind]string{}
65 for _, modelName := range models.ListModels() {
66 model := models.LookupModel(modelName)
67 if model == nil {
68 panic("ListModels returns a model that can't be looked-up.")
69 }
70 gvkList := parseGroupVersionKind(model)
71 for _, gvk := range gvkList {
72 if len(gvk.Kind) > 0 {
73 resources[gvk] = modelName
74 }
75 }
76 }
77
78 return &document{
79 resources: resources,
80 models: models,
81 doc: doc,
82 }, nil
83 }
84
85 func (d *document) LookupResource(gvk schema.GroupVersionKind) proto.Schema {
86 modelName, found := d.resources[gvk]
87 if !found {
88 return nil
89 }
90 return d.models.LookupModel(modelName)
91 }
92
93 func (d *document) GetConsumes(gvk schema.GroupVersionKind, operation string) []string {
94 for _, path := range d.doc.GetPaths().GetPath() {
95 for _, ex := range path.GetValue().GetPatch().GetVendorExtension() {
96 if ex.GetValue().GetYaml() == "" ||
97 ex.GetName() != "x-kubernetes-group-version-kind" {
98 continue
99 }
100
101 var value map[string]string
102 err := yaml.Unmarshal([]byte(ex.GetValue().GetYaml()), &value)
103 if err != nil {
104 continue
105 }
106
107 if value["group"] == gvk.Group && value["kind"] == gvk.Kind && value["version"] == gvk.Version {
108 switch operation {
109 case "GET":
110 return path.GetValue().GetGet().GetConsumes()
111 case "PATCH":
112 return path.GetValue().GetPatch().GetConsumes()
113 case "HEAD":
114 return path.GetValue().GetHead().GetConsumes()
115 case "PUT":
116 return path.GetValue().GetPut().GetConsumes()
117 case "POST":
118 return path.GetValue().GetPost().GetConsumes()
119 case "OPTIONS":
120 return path.GetValue().GetOptions().GetConsumes()
121 case "DELETE":
122 return path.GetValue().GetDelete().GetConsumes()
123 }
124 }
125 }
126 }
127
128 return nil
129 }
130
131
132 func parseGroupVersionKind(s proto.Schema) []schema.GroupVersionKind {
133 extensions := s.GetExtensions()
134
135 gvkListResult := []schema.GroupVersionKind{}
136
137
138 gvkExtension, ok := extensions[groupVersionKindExtensionKey]
139 if !ok {
140 return []schema.GroupVersionKind{}
141 }
142
143
144 gvkList, ok := gvkExtension.([]interface{})
145 if !ok {
146 return []schema.GroupVersionKind{}
147 }
148
149 for _, gvk := range gvkList {
150
151
152 gvkMap, ok := gvk.(map[interface{}]interface{})
153 if !ok {
154 continue
155 }
156 group, ok := gvkMap["group"].(string)
157 if !ok {
158 continue
159 }
160 version, ok := gvkMap["version"].(string)
161 if !ok {
162 continue
163 }
164 kind, ok := gvkMap["kind"].(string)
165 if !ok {
166 continue
167 }
168
169 gvkListResult = append(gvkListResult, schema.GroupVersionKind{
170 Group: group,
171 Version: version,
172 Kind: kind,
173 })
174 }
175
176 return gvkListResult
177 }
178
View as plain text