walker.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package schemamutation
  14. import (
  15. "k8s.io/kube-openapi/pkg/validation/spec"
  16. )
  17. // Walker runs callback functions on all references of an OpenAPI spec,
  18. // replacing the values when visiting corresponding types.
  19. type Walker struct {
  20. // SchemaCallback will be called on each schema, taking the original schema,
  21. // and before any other callbacks of the Walker.
  22. // If the schema needs to be mutated, DO NOT mutate it in-place,
  23. // always create a copy, mutate, and return it.
  24. SchemaCallback func(schema *spec.Schema) *spec.Schema
  25. // RefCallback will be called on each ref.
  26. // If the ref needs to be mutated, DO NOT mutate it in-place,
  27. // always create a copy, mutate, and return it.
  28. RefCallback func(ref *spec.Ref) *spec.Ref
  29. }
  30. type SchemaCallbackFunc func(schema *spec.Schema) *spec.Schema
  31. type RefCallbackFunc func(ref *spec.Ref) *spec.Ref
  32. var SchemaCallBackNoop SchemaCallbackFunc = func(schema *spec.Schema) *spec.Schema {
  33. return schema
  34. }
  35. var RefCallbackNoop RefCallbackFunc = func(ref *spec.Ref) *spec.Ref {
  36. return ref
  37. }
  38. // ReplaceReferences rewrites the references without mutating the input.
  39. // The output might share data with the input.
  40. func ReplaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
  41. walker := &Walker{RefCallback: walkRef, SchemaCallback: SchemaCallBackNoop}
  42. return walker.WalkRoot(sp)
  43. }
  44. func (w *Walker) WalkSchema(schema *spec.Schema) *spec.Schema {
  45. if schema == nil {
  46. return nil
  47. }
  48. orig := schema
  49. clone := func() {
  50. if orig == schema {
  51. schema = &spec.Schema{}
  52. *schema = *orig
  53. }
  54. }
  55. // Always run callback on the whole schema first
  56. // so that SchemaCallback can take the original schema as input.
  57. schema = w.SchemaCallback(schema)
  58. if r := w.RefCallback(&schema.Ref); r != &schema.Ref {
  59. clone()
  60. schema.Ref = *r
  61. }
  62. definitionsCloned := false
  63. for k, v := range schema.Definitions {
  64. if s := w.WalkSchema(&v); s != &v {
  65. if !definitionsCloned {
  66. definitionsCloned = true
  67. clone()
  68. schema.Definitions = make(spec.Definitions, len(orig.Definitions))
  69. for k2, v2 := range orig.Definitions {
  70. schema.Definitions[k2] = v2
  71. }
  72. }
  73. schema.Definitions[k] = *s
  74. }
  75. }
  76. propertiesCloned := false
  77. for k, v := range schema.Properties {
  78. if s := w.WalkSchema(&v); s != &v {
  79. if !propertiesCloned {
  80. propertiesCloned = true
  81. clone()
  82. schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
  83. for k2, v2 := range orig.Properties {
  84. schema.Properties[k2] = v2
  85. }
  86. }
  87. schema.Properties[k] = *s
  88. }
  89. }
  90. patternPropertiesCloned := false
  91. for k, v := range schema.PatternProperties {
  92. if s := w.WalkSchema(&v); s != &v {
  93. if !patternPropertiesCloned {
  94. patternPropertiesCloned = true
  95. clone()
  96. schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
  97. for k2, v2 := range orig.PatternProperties {
  98. schema.PatternProperties[k2] = v2
  99. }
  100. }
  101. schema.PatternProperties[k] = *s
  102. }
  103. }
  104. allOfCloned := false
  105. for i := range schema.AllOf {
  106. if s := w.WalkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
  107. if !allOfCloned {
  108. allOfCloned = true
  109. clone()
  110. schema.AllOf = make([]spec.Schema, len(orig.AllOf))
  111. copy(schema.AllOf, orig.AllOf)
  112. }
  113. schema.AllOf[i] = *s
  114. }
  115. }
  116. anyOfCloned := false
  117. for i := range schema.AnyOf {
  118. if s := w.WalkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
  119. if !anyOfCloned {
  120. anyOfCloned = true
  121. clone()
  122. schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
  123. copy(schema.AnyOf, orig.AnyOf)
  124. }
  125. schema.AnyOf[i] = *s
  126. }
  127. }
  128. oneOfCloned := false
  129. for i := range schema.OneOf {
  130. if s := w.WalkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
  131. if !oneOfCloned {
  132. oneOfCloned = true
  133. clone()
  134. schema.OneOf = make([]spec.Schema, len(orig.OneOf))
  135. copy(schema.OneOf, orig.OneOf)
  136. }
  137. schema.OneOf[i] = *s
  138. }
  139. }
  140. if schema.Not != nil {
  141. if s := w.WalkSchema(schema.Not); s != schema.Not {
  142. clone()
  143. schema.Not = s
  144. }
  145. }
  146. if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
  147. if s := w.WalkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
  148. clone()
  149. schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
  150. }
  151. }
  152. if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
  153. if s := w.WalkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
  154. clone()
  155. schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
  156. }
  157. }
  158. if schema.Items != nil {
  159. if schema.Items.Schema != nil {
  160. if s := w.WalkSchema(schema.Items.Schema); s != schema.Items.Schema {
  161. clone()
  162. schema.Items = &spec.SchemaOrArray{Schema: s}
  163. }
  164. } else {
  165. itemsCloned := false
  166. for i := range schema.Items.Schemas {
  167. if s := w.WalkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
  168. if !itemsCloned {
  169. clone()
  170. schema.Items = &spec.SchemaOrArray{
  171. Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
  172. }
  173. itemsCloned = true
  174. copy(schema.Items.Schemas, orig.Items.Schemas)
  175. }
  176. schema.Items.Schemas[i] = *s
  177. }
  178. }
  179. }
  180. }
  181. return schema
  182. }
  183. func (w *Walker) walkParameter(param *spec.Parameter) *spec.Parameter {
  184. if param == nil {
  185. return nil
  186. }
  187. orig := param
  188. cloned := false
  189. clone := func() {
  190. if !cloned {
  191. cloned = true
  192. param = &spec.Parameter{}
  193. *param = *orig
  194. }
  195. }
  196. if r := w.RefCallback(&param.Ref); r != &param.Ref {
  197. clone()
  198. param.Ref = *r
  199. }
  200. if s := w.WalkSchema(param.Schema); s != param.Schema {
  201. clone()
  202. param.Schema = s
  203. }
  204. if param.Items != nil {
  205. if r := w.RefCallback(&param.Items.Ref); r != &param.Items.Ref {
  206. param.Items.Ref = *r
  207. }
  208. }
  209. return param
  210. }
  211. func (w *Walker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
  212. if params == nil {
  213. return nil, false
  214. }
  215. orig := params
  216. cloned := false
  217. clone := func() {
  218. if !cloned {
  219. cloned = true
  220. params = make([]spec.Parameter, len(params))
  221. copy(params, orig)
  222. }
  223. }
  224. for i := range params {
  225. if s := w.walkParameter(&params[i]); s != &params[i] {
  226. clone()
  227. params[i] = *s
  228. }
  229. }
  230. return params, cloned
  231. }
  232. func (w *Walker) walkResponse(resp *spec.Response) *spec.Response {
  233. if resp == nil {
  234. return nil
  235. }
  236. orig := resp
  237. cloned := false
  238. clone := func() {
  239. if !cloned {
  240. cloned = true
  241. resp = &spec.Response{}
  242. *resp = *orig
  243. }
  244. }
  245. if r := w.RefCallback(&resp.Ref); r != &resp.Ref {
  246. clone()
  247. resp.Ref = *r
  248. }
  249. if s := w.WalkSchema(resp.Schema); s != resp.Schema {
  250. clone()
  251. resp.Schema = s
  252. }
  253. return resp
  254. }
  255. func (w *Walker) walkResponses(resps *spec.Responses) *spec.Responses {
  256. if resps == nil {
  257. return nil
  258. }
  259. orig := resps
  260. cloned := false
  261. clone := func() {
  262. if !cloned {
  263. cloned = true
  264. resps = &spec.Responses{}
  265. *resps = *orig
  266. }
  267. }
  268. if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
  269. clone()
  270. resps.Default = r
  271. }
  272. responsesCloned := false
  273. for k, v := range resps.ResponsesProps.StatusCodeResponses {
  274. if r := w.walkResponse(&v); r != &v {
  275. if !responsesCloned {
  276. responsesCloned = true
  277. clone()
  278. resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
  279. for k2, v2 := range orig.StatusCodeResponses {
  280. resps.ResponsesProps.StatusCodeResponses[k2] = v2
  281. }
  282. }
  283. resps.ResponsesProps.StatusCodeResponses[k] = *r
  284. }
  285. }
  286. return resps
  287. }
  288. func (w *Walker) walkOperation(op *spec.Operation) *spec.Operation {
  289. if op == nil {
  290. return nil
  291. }
  292. orig := op
  293. cloned := false
  294. clone := func() {
  295. if !cloned {
  296. cloned = true
  297. op = &spec.Operation{}
  298. *op = *orig
  299. }
  300. }
  301. parametersCloned := false
  302. for i := range op.Parameters {
  303. if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
  304. if !parametersCloned {
  305. parametersCloned = true
  306. clone()
  307. op.Parameters = make([]spec.Parameter, len(orig.Parameters))
  308. copy(op.Parameters, orig.Parameters)
  309. }
  310. op.Parameters[i] = *s
  311. }
  312. }
  313. if r := w.walkResponses(op.Responses); r != op.Responses {
  314. clone()
  315. op.Responses = r
  316. }
  317. return op
  318. }
  319. func (w *Walker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
  320. if pathItem == nil {
  321. return nil
  322. }
  323. orig := pathItem
  324. cloned := false
  325. clone := func() {
  326. if !cloned {
  327. cloned = true
  328. pathItem = &spec.PathItem{}
  329. *pathItem = *orig
  330. }
  331. }
  332. if p, changed := w.walkParameters(pathItem.Parameters); changed {
  333. clone()
  334. pathItem.Parameters = p
  335. }
  336. if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
  337. clone()
  338. pathItem.Get = op
  339. }
  340. if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
  341. clone()
  342. pathItem.Head = op
  343. }
  344. if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
  345. clone()
  346. pathItem.Delete = op
  347. }
  348. if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
  349. clone()
  350. pathItem.Options = op
  351. }
  352. if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
  353. clone()
  354. pathItem.Patch = op
  355. }
  356. if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
  357. clone()
  358. pathItem.Post = op
  359. }
  360. if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
  361. clone()
  362. pathItem.Put = op
  363. }
  364. return pathItem
  365. }
  366. func (w *Walker) walkPaths(paths *spec.Paths) *spec.Paths {
  367. if paths == nil {
  368. return nil
  369. }
  370. orig := paths
  371. cloned := false
  372. clone := func() {
  373. if !cloned {
  374. cloned = true
  375. paths = &spec.Paths{}
  376. *paths = *orig
  377. }
  378. }
  379. pathsCloned := false
  380. for k, v := range paths.Paths {
  381. if p := w.walkPathItem(&v); p != &v {
  382. if !pathsCloned {
  383. pathsCloned = true
  384. clone()
  385. paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
  386. for k2, v2 := range orig.Paths {
  387. paths.Paths[k2] = v2
  388. }
  389. }
  390. paths.Paths[k] = *p
  391. }
  392. }
  393. return paths
  394. }
  395. func (w *Walker) WalkRoot(swagger *spec.Swagger) *spec.Swagger {
  396. if swagger == nil {
  397. return nil
  398. }
  399. orig := swagger
  400. cloned := false
  401. clone := func() {
  402. if !cloned {
  403. cloned = true
  404. swagger = &spec.Swagger{}
  405. *swagger = *orig
  406. }
  407. }
  408. parametersCloned := false
  409. for k, v := range swagger.Parameters {
  410. if p := w.walkParameter(&v); p != &v {
  411. if !parametersCloned {
  412. parametersCloned = true
  413. clone()
  414. swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
  415. for k2, v2 := range orig.Parameters {
  416. swagger.Parameters[k2] = v2
  417. }
  418. }
  419. swagger.Parameters[k] = *p
  420. }
  421. }
  422. responsesCloned := false
  423. for k, v := range swagger.Responses {
  424. if r := w.walkResponse(&v); r != &v {
  425. if !responsesCloned {
  426. responsesCloned = true
  427. clone()
  428. swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
  429. for k2, v2 := range orig.Responses {
  430. swagger.Responses[k2] = v2
  431. }
  432. }
  433. swagger.Responses[k] = *r
  434. }
  435. }
  436. definitionsCloned := false
  437. for k, v := range swagger.Definitions {
  438. if s := w.WalkSchema(&v); s != &v {
  439. if !definitionsCloned {
  440. definitionsCloned = true
  441. clone()
  442. swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
  443. for k2, v2 := range orig.Definitions {
  444. swagger.Definitions[k2] = v2
  445. }
  446. }
  447. swagger.Definitions[k] = *s
  448. }
  449. }
  450. if swagger.Paths != nil {
  451. if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
  452. clone()
  453. swagger.Paths = p
  454. }
  455. }
  456. return swagger
  457. }