add prune and remove unused packages
This commit is contained in:
20
vendor/k8s.io/kube-openapi/.gitignore
generated
vendored
20
vendor/k8s.io/kube-openapi/.gitignore
generated
vendored
@@ -1,20 +0,0 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
# Intellij IDEA files
|
||||
.idea/
|
||||
*.iml
|
||||
.vscode
|
||||
|
4
vendor/k8s.io/kube-openapi/.travis.yml
generated
vendored
4
vendor/k8s.io/kube-openapi/.travis.yml
generated
vendored
@@ -1,4 +0,0 @@
|
||||
language: go
|
||||
go_import_path: k8s.io/kube-openapi
|
||||
script: go test ./pkg/... ./test/...
|
||||
|
9
vendor/k8s.io/kube-openapi/CONTRIBUTING.md
generated
vendored
9
vendor/k8s.io/kube-openapi/CONTRIBUTING.md
generated
vendored
@@ -1,9 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Thanks for taking the time to join our community and start contributing!
|
||||
|
||||
The [Contributor Guide](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md)
|
||||
provides detailed instructions on how to get your ideas and bug fixes seen and accepted.
|
||||
|
||||
Please remember to sign the [CNCF CLA](https://github.com/kubernetes/community/blob/master/CLA.md) and
|
||||
read and observe the [Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
401
vendor/k8s.io/kube-openapi/Godeps/Godeps.json
generated
vendored
401
vendor/k8s.io/kube-openapi/Godeps/Godeps.json
generated
vendored
@@ -1,401 +0,0 @@
|
||||
{
|
||||
"ImportPath": "k8s.io/kube-openapi",
|
||||
"GoVersion": "go1.8",
|
||||
"GodepVersion": "v79",
|
||||
"Packages": [
|
||||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "bitbucket.org/ww/goautoneg",
|
||||
"Comment": "null-5",
|
||||
"Rev": "75cd24fc2f2c2a2088577d12123ddee5f54e0675"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/NYTimes/gziphandler",
|
||||
"Rev": "56545f4a5d46df9a6648819d1664c3a03a13ffdb"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/PuerkitoBio/purell",
|
||||
"Comment": "v1.0.0",
|
||||
"Rev": "8a290539e2e8629dbc4e6bad948158f790ec31f4"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
||||
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/davecgh/go-spew/spew",
|
||||
"Rev": "5215b55f46b2b919f50a1df0eaa5886afe4e3b3d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful",
|
||||
"Comment": "2.2.0-4-gff4f55a",
|
||||
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/emicklei/go-restful/log",
|
||||
"Comment": "2.2.0-4-gff4f55a",
|
||||
"Rev": "ff4f55a206334ef123e4f79bbf348980da81ca46"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/swag",
|
||||
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/proto",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/any",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/golang/protobuf/ptypes/timestamp",
|
||||
"Rev": "4bd1920723d7b7c925de087aa32e2187708897f7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/compiler",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/googleapis/gnostic/extensions",
|
||||
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/buffer",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/jlexer",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/mailru/easyjson/jwriter",
|
||||
"Rev": "d5b7844b561a7bc640052f1b935f7b800330d7e0"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/config",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/codelocation",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/containernode",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/failer",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/leafnodes",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/remote",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/spec",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/spec_iterator",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/specrunner",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/suite",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/testingtproxy",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/internal/writer",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/reporters",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/reporters/stenographer",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/ginkgo/types",
|
||||
"Comment": "v1.4.0-4-g11459a8",
|
||||
"Rev": "11459a886d9cd66b319dac7ef1e917ee221372c9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/format",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/internal/assertion",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/internal/asyncassertion",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/internal/oraclematcher",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/internal/testingtsupport",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/matchers",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/edge",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/node",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/util",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/onsi/gomega/types",
|
||||
"Comment": "v1.2.0-2-gdcabb60",
|
||||
"Rev": "dcabb60a477c2b6f456df65037cb6708210fbb02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/pmezard/go-difflib/difflib",
|
||||
"Rev": "d8ed2627bdf02c080bf22230dbb337003b7aba2d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/spf13/pflag",
|
||||
"Rev": "9ff6c6923cfffbcd502984b8e0c80539a94968b7"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/assert",
|
||||
"Comment": "v1.0-88-ge3a8ff8",
|
||||
"Rev": "e3a8ff8ce36581f87a15341206f205b1da467059"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html/atom",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/html/charset",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/net/idna",
|
||||
"Rev": "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/sys/unix",
|
||||
"Rev": "bb24a47a89eac6c1227fbcb2ae37a8b9ed323366"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/cases",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/charmap",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/htmlindex",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/internal",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/internal/identifier",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/japanese",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/korean",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/simplifiedchinese",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/traditionalchinese",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/encoding/unicode",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal/tag",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/internal/utf8internal",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/language",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/runes",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/secure/bidirule",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/secure/precis",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/transform",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/unicode/bidi",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/unicode/norm",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "golang.org/x/text/width",
|
||||
"Rev": "2910a502d2bf9e43193af9d68ca516529614eed3"
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/yaml.v2",
|
||||
"Rev": "53feefa2559fb8dfa8d81baad31be332c97d6c77"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo/args",
|
||||
"Rev": "75356185a9af8f0464efa792e2e9508d5b4be83c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo/generator",
|
||||
"Rev": "75356185a9af8f0464efa792e2e9508d5b4be83c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo/namer",
|
||||
"Rev": "75356185a9af8f0464efa792e2e9508d5b4be83c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo/parser",
|
||||
"Rev": "75356185a9af8f0464efa792e2e9508d5b4be83c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/gengo/types",
|
||||
"Rev": "75356185a9af8f0464efa792e2e9508d5b4be83c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "k8s.io/klog",
|
||||
"Rev": "b9b56d5dfc9208f60ea747056670942d8b0afdc8"
|
||||
}
|
||||
]
|
||||
}
|
5
vendor/k8s.io/kube-openapi/Godeps/Readme
generated
vendored
5
vendor/k8s.io/kube-openapi/Godeps/Readme
generated
vendored
@@ -1,5 +0,0 @@
|
||||
This directory tree is generated automatically by godep.
|
||||
|
||||
Please do not edit.
|
||||
|
||||
See https://github.com/tools/godep for more information.
|
12
vendor/k8s.io/kube-openapi/OWNERS
generated
vendored
12
vendor/k8s.io/kube-openapi/OWNERS
generated
vendored
@@ -1,12 +0,0 @@
|
||||
reviewers:
|
||||
- yujuhong
|
||||
- gmarek
|
||||
- mbohlool
|
||||
- philips
|
||||
- seans3
|
||||
- apelisse
|
||||
- roycaihw
|
||||
approvers:
|
||||
- mbohlool
|
||||
- lavalamp
|
||||
- seans3
|
18
vendor/k8s.io/kube-openapi/README.md
generated
vendored
18
vendor/k8s.io/kube-openapi/README.md
generated
vendored
@@ -1,18 +0,0 @@
|
||||
# Kube OpenAPI
|
||||
|
||||
This repo is the home for Kubernetes OpenAPI discovery spec generation. The goal
|
||||
is to support a subset of OpenAPI features to satisfy kubernetes use-cases but
|
||||
implement that subset with little to no assumption about the structure of the
|
||||
code or routes. Thus, there should be no kubernetes specific code in this repo.
|
||||
|
||||
|
||||
There are two main parts:
|
||||
- A model generator that goes through .go files, find and generate model
|
||||
definitions.
|
||||
- The spec generator that is responsible for dynamically generate
|
||||
the final OpenAPI spec using web service routes or combining other
|
||||
OpenAPI/Json specs.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for instructions on how to contribute.
|
73
vendor/k8s.io/kube-openapi/cmd/openapi-gen/args/args.go
generated
vendored
73
vendor/k8s.io/kube-openapi/cmd/openapi-gen/args/args.go
generated
vendored
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 args
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/gengo/args"
|
||||
)
|
||||
|
||||
// CustomArgs is used by the gengo framework to pass args specific to this generator.
|
||||
type CustomArgs struct {
|
||||
// ReportFilename is added to CustomArgs for specifying name of report file used
|
||||
// by API linter. If specified, API rule violations will be printed to report file.
|
||||
// Otherwise default value "-" will be used which indicates stdout.
|
||||
ReportFilename string
|
||||
}
|
||||
|
||||
// NewDefaults returns default arguments for the generator. Returning the arguments instead
|
||||
// of using default flag parsing allows registering custom arguments afterwards
|
||||
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
|
||||
// Default() sets a couple of flag default values for example the boilerplate.
|
||||
// WithoutDefaultFlagParsing() disables implicit addition of command line flags and parsing,
|
||||
// which allows registering custom arguments afterwards
|
||||
genericArgs := args.Default().WithoutDefaultFlagParsing()
|
||||
customArgs := &CustomArgs{}
|
||||
genericArgs.CustomArgs = customArgs
|
||||
|
||||
// Default value for report filename is "-", which stands for stdout
|
||||
customArgs.ReportFilename = "-"
|
||||
// Default value for output file base name
|
||||
genericArgs.OutputFileBaseName = "openapi_generated"
|
||||
|
||||
return genericArgs, customArgs
|
||||
}
|
||||
|
||||
// AddFlags add the generator flags to the flag set.
|
||||
func (c *CustomArgs) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVarP(&c.ReportFilename, "report-filename", "r", c.ReportFilename, "Name of report file used by API linter to print API violations. Default \"-\" stands for standard output. NOTE that if valid filename other than \"-\" is specified, API linter won't return error on detected API violations. This allows further check of existing API violations without stopping the OpenAPI generation toolchain.")
|
||||
}
|
||||
|
||||
// Validate checks the given arguments.
|
||||
func Validate(genericArgs *args.GeneratorArgs) error {
|
||||
c, ok := genericArgs.CustomArgs.(*CustomArgs)
|
||||
if !ok {
|
||||
return fmt.Errorf("input arguments don't contain valid custom arguments")
|
||||
}
|
||||
if len(c.ReportFilename) == 0 {
|
||||
return fmt.Errorf("report filename cannot be empty. specify a valid filename or use \"-\" for stdout")
|
||||
}
|
||||
if len(genericArgs.OutputFileBaseName) == 0 {
|
||||
return fmt.Errorf("output file base name cannot be empty")
|
||||
}
|
||||
if len(genericArgs.OutputPackagePath) == 0 {
|
||||
return fmt.Errorf("output package cannot be empty")
|
||||
}
|
||||
return nil
|
||||
}
|
58
vendor/k8s.io/kube-openapi/cmd/openapi-gen/openapi-gen.go
generated
vendored
58
vendor/k8s.io/kube-openapi/cmd/openapi-gen/openapi-gen.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// This package generates openAPI definition file to be used in open API spec generation on API servers. To generate
|
||||
// definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines. To
|
||||
// exclude a type from a tagged package, add "+k8s:openapi-gen=false" tag to the type comment lines.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
generatorargs "k8s.io/kube-openapi/cmd/openapi-gen/args"
|
||||
"k8s.io/kube-openapi/pkg/generators"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
klog.InitFlags(nil)
|
||||
genericArgs, customArgs := generatorargs.NewDefaults()
|
||||
|
||||
genericArgs.AddFlags(pflag.CommandLine)
|
||||
customArgs.AddFlags(pflag.CommandLine)
|
||||
flag.Set("logtostderr", "true")
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
pflag.Parse()
|
||||
|
||||
if err := generatorargs.Validate(genericArgs); err != nil {
|
||||
log.Fatalf("Arguments validation error: %v", err)
|
||||
}
|
||||
|
||||
// Generates the code for the OpenAPIDefinitions.
|
||||
if err := genericArgs.Execute(
|
||||
generators.NameSystems(),
|
||||
generators.DefaultNameSystem(),
|
||||
generators.Packages,
|
||||
); err != nil {
|
||||
log.Fatalf("OpenAPI code generation error: %v", err)
|
||||
}
|
||||
log.Println("Code for OpenAPI definitions generated")
|
||||
}
|
60
vendor/k8s.io/kube-openapi/cmd/openapi2smd/openapi2smd.go
generated
vendored
60
vendor/k8s.io/kube-openapi/cmd/openapi2smd/openapi2smd.go
generated
vendored
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/schemaconv"
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 1 {
|
||||
log.Fatal("this program takes input on stdin and writes output to stdout.")
|
||||
}
|
||||
|
||||
var info yaml.MapSlice
|
||||
if err := yaml.NewDecoder(os.Stdin).Decode(&info); err != nil {
|
||||
log.Fatalf("error decoding stdin: %v", err)
|
||||
}
|
||||
|
||||
document, err := openapi_v2.NewDocument(info, compiler.NewContext("$root", nil))
|
||||
if err != nil {
|
||||
log.Fatalf("error interpreting stdin: %v", err)
|
||||
}
|
||||
|
||||
models, err := proto.NewOpenAPIData(document)
|
||||
if err != nil {
|
||||
log.Fatalf("error interpreting models: %v", err)
|
||||
}
|
||||
|
||||
newSchema, err := schemaconv.ToSchema(models)
|
||||
if err != nil {
|
||||
log.Fatalf("error converting schema format: %v", err)
|
||||
}
|
||||
|
||||
if err := yaml.NewEncoder(os.Stdout).Encode(newSchema); err != nil {
|
||||
log.Fatalf("error writing new schema: %v", err)
|
||||
}
|
||||
|
||||
}
|
3
vendor/k8s.io/kube-openapi/code-of-conduct.md
generated
vendored
3
vendor/k8s.io/kube-openapi/code-of-conduct.md
generated
vendored
@@ -1,3 +0,0 @@
|
||||
# Kubernetes Community Code of Conduct
|
||||
|
||||
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
|
391
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
generated
vendored
391
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
generated
vendored
@@ -1,391 +0,0 @@
|
||||
/*
|
||||
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 aggregator
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
definitionPrefix = "#/definitions/"
|
||||
)
|
||||
|
||||
// Run a walkRefCallback method on all references of an OpenAPI spec
|
||||
type referenceWalker struct {
|
||||
// walkRefCallback will be called on each reference and the return value
|
||||
// will replace that reference. This will allow the callers to change
|
||||
// all/some references of an spec (e.g. useful in renaming definitions).
|
||||
walkRefCallback func(ref spec.Ref) spec.Ref
|
||||
|
||||
// The spec to walk through.
|
||||
root *spec.Swagger
|
||||
|
||||
// Keep track of visited references
|
||||
alreadyVisited map[string]bool
|
||||
}
|
||||
|
||||
func walkOnAllReferences(walkRef func(ref spec.Ref) spec.Ref, sp *spec.Swagger) {
|
||||
walker := &referenceWalker{walkRefCallback: walkRef, root: sp, alreadyVisited: map[string]bool{}}
|
||||
walker.Start()
|
||||
}
|
||||
|
||||
func (s *referenceWalker) walkRef(ref spec.Ref) spec.Ref {
|
||||
refStr := ref.String()
|
||||
// References that start with #/definitions/ has a definition
|
||||
// inside the same spec file. If that is the case, walk through
|
||||
// those definitions too.
|
||||
// We do not support external references yet.
|
||||
if !s.alreadyVisited[refStr] && strings.HasPrefix(refStr, definitionPrefix) {
|
||||
s.alreadyVisited[refStr] = true
|
||||
k := refStr[len(definitionPrefix):]
|
||||
def := s.root.Definitions[k]
|
||||
s.walkSchema(&def)
|
||||
// Make sure we don't assign to nil map
|
||||
if s.root.Definitions == nil {
|
||||
s.root.Definitions = spec.Definitions{}
|
||||
}
|
||||
s.root.Definitions[k] = def
|
||||
}
|
||||
return s.walkRefCallback(ref)
|
||||
}
|
||||
|
||||
func (s *referenceWalker) walkSchema(schema *spec.Schema) {
|
||||
if schema == nil {
|
||||
return
|
||||
}
|
||||
schema.Ref = s.walkRef(schema.Ref)
|
||||
for k, v := range schema.Definitions {
|
||||
s.walkSchema(&v)
|
||||
schema.Definitions[k] = v
|
||||
}
|
||||
for k, v := range schema.Properties {
|
||||
s.walkSchema(&v)
|
||||
schema.Properties[k] = v
|
||||
}
|
||||
for k, v := range schema.PatternProperties {
|
||||
s.walkSchema(&v)
|
||||
schema.PatternProperties[k] = v
|
||||
}
|
||||
for i := range schema.AllOf {
|
||||
s.walkSchema(&schema.AllOf[i])
|
||||
}
|
||||
for i := range schema.AnyOf {
|
||||
s.walkSchema(&schema.AnyOf[i])
|
||||
}
|
||||
for i := range schema.OneOf {
|
||||
s.walkSchema(&schema.OneOf[i])
|
||||
}
|
||||
if schema.Not != nil {
|
||||
s.walkSchema(schema.Not)
|
||||
}
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
s.walkSchema(schema.AdditionalProperties.Schema)
|
||||
}
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
s.walkSchema(schema.AdditionalItems.Schema)
|
||||
}
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
s.walkSchema(schema.Items.Schema)
|
||||
}
|
||||
for i := range schema.Items.Schemas {
|
||||
s.walkSchema(&schema.Items.Schemas[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *referenceWalker) walkParams(params []spec.Parameter) {
|
||||
if params == nil {
|
||||
return
|
||||
}
|
||||
for _, param := range params {
|
||||
param.Ref = s.walkRef(param.Ref)
|
||||
s.walkSchema(param.Schema)
|
||||
if param.Items != nil {
|
||||
param.Items.Ref = s.walkRef(param.Items.Ref)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *referenceWalker) walkResponse(resp *spec.Response) {
|
||||
if resp == nil {
|
||||
return
|
||||
}
|
||||
resp.Ref = s.walkRef(resp.Ref)
|
||||
s.walkSchema(resp.Schema)
|
||||
}
|
||||
|
||||
func (s *referenceWalker) walkOperation(op *spec.Operation) {
|
||||
if op == nil {
|
||||
return
|
||||
}
|
||||
s.walkParams(op.Parameters)
|
||||
if op.Responses == nil {
|
||||
return
|
||||
}
|
||||
s.walkResponse(op.Responses.Default)
|
||||
for _, r := range op.Responses.StatusCodeResponses {
|
||||
s.walkResponse(&r)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *referenceWalker) Start() {
|
||||
if s.root.Paths == nil {
|
||||
return
|
||||
}
|
||||
for _, pathItem := range s.root.Paths.Paths {
|
||||
s.walkParams(pathItem.Parameters)
|
||||
s.walkOperation(pathItem.Delete)
|
||||
s.walkOperation(pathItem.Get)
|
||||
s.walkOperation(pathItem.Head)
|
||||
s.walkOperation(pathItem.Options)
|
||||
s.walkOperation(pathItem.Patch)
|
||||
s.walkOperation(pathItem.Post)
|
||||
s.walkOperation(pathItem.Put)
|
||||
}
|
||||
}
|
||||
|
||||
// usedDefinitionForSpec returns a map with all used definitions in the provided spec as keys and true as values.
|
||||
func usedDefinitionForSpec(sp *spec.Swagger) map[string]bool {
|
||||
usedDefinitions := map[string]bool{}
|
||||
walkOnAllReferences(func(ref spec.Ref) spec.Ref {
|
||||
if refStr := ref.String(); refStr != "" && strings.HasPrefix(refStr, definitionPrefix) {
|
||||
usedDefinitions[refStr[len(definitionPrefix):]] = true
|
||||
}
|
||||
return ref
|
||||
}, sp)
|
||||
return usedDefinitions
|
||||
}
|
||||
|
||||
// FilterSpecByPaths removes unnecessary paths and definitions used by those paths.
|
||||
// i.e. if a Path removed by this function, all definitions used by it and not used
|
||||
// anywhere else will also be removed.
|
||||
func FilterSpecByPaths(sp *spec.Swagger, keepPathPrefixes []string) {
|
||||
// Walk all references to find all used definitions. This function
|
||||
// want to only deal with unused definitions resulted from filtering paths.
|
||||
// Thus a definition will be removed only if it has been used before but
|
||||
// it is unused because of a path prune.
|
||||
initialUsedDefinitions := usedDefinitionForSpec(sp)
|
||||
|
||||
// First remove unwanted paths
|
||||
prefixes := util.NewTrie(keepPathPrefixes)
|
||||
orgPaths := sp.Paths
|
||||
if orgPaths == nil {
|
||||
return
|
||||
}
|
||||
sp.Paths = &spec.Paths{
|
||||
VendorExtensible: orgPaths.VendorExtensible,
|
||||
Paths: map[string]spec.PathItem{},
|
||||
}
|
||||
for path, pathItem := range orgPaths.Paths {
|
||||
if !prefixes.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
sp.Paths.Paths[path] = pathItem
|
||||
}
|
||||
|
||||
// Walk all references to find all definition references.
|
||||
usedDefinitions := usedDefinitionForSpec(sp)
|
||||
|
||||
// Remove unused definitions
|
||||
orgDefinitions := sp.Definitions
|
||||
sp.Definitions = spec.Definitions{}
|
||||
for k, v := range orgDefinitions {
|
||||
if usedDefinitions[k] || !initialUsedDefinitions[k] {
|
||||
sp.Definitions[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func renameDefinition(s *spec.Swagger, old, new string) {
|
||||
oldRef := definitionPrefix + old
|
||||
newRef := definitionPrefix + new
|
||||
walkOnAllReferences(func(ref spec.Ref) spec.Ref {
|
||||
if ref.String() == oldRef {
|
||||
return spec.MustCreateRef(newRef)
|
||||
}
|
||||
return ref
|
||||
}, s)
|
||||
// Make sure we don't assign to nil map
|
||||
if s.Definitions == nil {
|
||||
s.Definitions = spec.Definitions{}
|
||||
}
|
||||
s.Definitions[new] = s.Definitions[old]
|
||||
delete(s.Definitions, old)
|
||||
}
|
||||
|
||||
// MergeSpecsIgnorePathConflict is the same as MergeSpecs except it will ignore any path
|
||||
// conflicts by keeping the paths of destination. It will rename definition conflicts.
|
||||
func MergeSpecsIgnorePathConflict(dest, source *spec.Swagger) error {
|
||||
return mergeSpecs(dest, source, true, true)
|
||||
}
|
||||
|
||||
// MergeSpecsFailOnDefinitionConflict is differ from MergeSpecs as it fails if there is
|
||||
// a definition conflict.
|
||||
func MergeSpecsFailOnDefinitionConflict(dest, source *spec.Swagger) error {
|
||||
return mergeSpecs(dest, source, false, false)
|
||||
}
|
||||
|
||||
// MergeSpecs copies paths and definitions from source to dest, rename definitions if needed.
|
||||
// dest will be mutated, and source will not be changed. It will fail on path conflicts.
|
||||
func MergeSpecs(dest, source *spec.Swagger) error {
|
||||
return mergeSpecs(dest, source, true, false)
|
||||
}
|
||||
|
||||
func mergeSpecs(dest, source *spec.Swagger, renameModelConflicts, ignorePathConflicts bool) (err error) {
|
||||
specCloned := false
|
||||
// Paths may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
if source.Paths == nil {
|
||||
// When a source spec does not have any path, that means none of the definitions
|
||||
// are used thus we should not do anything
|
||||
return nil
|
||||
}
|
||||
if dest.Paths == nil {
|
||||
dest.Paths = &spec.Paths{}
|
||||
}
|
||||
if ignorePathConflicts {
|
||||
keepPaths := []string{}
|
||||
hasConflictingPath := false
|
||||
for k := range source.Paths.Paths {
|
||||
if _, found := dest.Paths.Paths[k]; !found {
|
||||
keepPaths = append(keepPaths, k)
|
||||
} else {
|
||||
hasConflictingPath = true
|
||||
}
|
||||
}
|
||||
if len(keepPaths) == 0 {
|
||||
// There is nothing to merge. All paths are conflicting.
|
||||
return nil
|
||||
}
|
||||
if hasConflictingPath {
|
||||
source, err = CloneSpec(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
specCloned = true
|
||||
FilterSpecByPaths(source, keepPaths)
|
||||
}
|
||||
}
|
||||
// Check for model conflicts
|
||||
conflicts := false
|
||||
for k, v := range source.Definitions {
|
||||
v2, found := dest.Definitions[k]
|
||||
if found && !reflect.DeepEqual(v, v2) {
|
||||
if !renameModelConflicts {
|
||||
return fmt.Errorf("model name conflict in merging OpenAPI spec: %s", k)
|
||||
}
|
||||
conflicts = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if conflicts {
|
||||
if !specCloned {
|
||||
source, err = CloneSpec(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
specCloned = true
|
||||
usedNames := map[string]bool{}
|
||||
for k := range dest.Definitions {
|
||||
usedNames[k] = true
|
||||
}
|
||||
type Rename struct {
|
||||
from, to string
|
||||
}
|
||||
renames := []Rename{}
|
||||
|
||||
OUTERLOOP:
|
||||
for k, v := range source.Definitions {
|
||||
if usedNames[k] {
|
||||
v2, found := dest.Definitions[k]
|
||||
// Reuse model if they are exactly the same.
|
||||
if found && reflect.DeepEqual(v, v2) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Reuse previously renamed model if one exists
|
||||
var newName string
|
||||
i := 1
|
||||
for found {
|
||||
i++
|
||||
newName = fmt.Sprintf("%s_v%d", k, i)
|
||||
v2, found = dest.Definitions[newName]
|
||||
if found && reflect.DeepEqual(v, v2) {
|
||||
renames = append(renames, Rename{from: k, to: newName})
|
||||
continue OUTERLOOP
|
||||
}
|
||||
}
|
||||
|
||||
_, foundInSource := source.Definitions[newName]
|
||||
for usedNames[newName] || foundInSource {
|
||||
i++
|
||||
newName = fmt.Sprintf("%s_v%d", k, i)
|
||||
_, foundInSource = source.Definitions[newName]
|
||||
}
|
||||
renames = append(renames, Rename{from: k, to: newName})
|
||||
usedNames[newName] = true
|
||||
}
|
||||
}
|
||||
for _, r := range renames {
|
||||
renameDefinition(source, r.from, r.to)
|
||||
}
|
||||
}
|
||||
for k, v := range source.Definitions {
|
||||
if _, found := dest.Definitions[k]; !found {
|
||||
if dest.Definitions == nil {
|
||||
dest.Definitions = spec.Definitions{}
|
||||
}
|
||||
dest.Definitions[k] = v
|
||||
}
|
||||
}
|
||||
// Check for path conflicts
|
||||
for k, v := range source.Paths.Paths {
|
||||
if _, found := dest.Paths.Paths[k]; found {
|
||||
return fmt.Errorf("unable to merge: duplicated path %s", k)
|
||||
}
|
||||
// PathItem may be empty, due to [ACL constraints](http://goo.gl/8us55a#securityFiltering).
|
||||
if dest.Paths.Paths == nil {
|
||||
dest.Paths.Paths = map[string]spec.PathItem{}
|
||||
}
|
||||
dest.Paths.Paths[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloneSpec clones OpenAPI spec
|
||||
func CloneSpec(source *spec.Swagger) (*spec.Swagger, error) {
|
||||
// TODO(mehdy): Find a faster way to clone an spec
|
||||
bytes, err := json.Marshal(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ret spec.Swagger
|
||||
err = json.Unmarshal(bytes, &ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
1858
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator_test.go
generated
vendored
1858
vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator_test.go
generated
vendored
File diff suppressed because it is too large
Load Diff
20
vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
20
vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 builder contains code to generate OpenAPI discovery spec (which
|
||||
// initial version of it also known as Swagger 2.0).
|
||||
// For more details: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
|
||||
package builder
|
442
vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
442
vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
@@ -1,442 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 builder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenAPIVersion = "2.0"
|
||||
// TODO: Make this configurable.
|
||||
extensionPrefix = "x-kubernetes-"
|
||||
)
|
||||
|
||||
type openAPI struct {
|
||||
config *common.Config
|
||||
swagger *spec.Swagger
|
||||
protocolList []string
|
||||
definitions map[string]common.OpenAPIDefinition
|
||||
}
|
||||
|
||||
// BuildOpenAPISpec builds OpenAPI spec given a list of webservices (containing routes) and common.Config to customize it.
|
||||
func BuildOpenAPISpec(webServices []*restful.WebService, config *common.Config) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
err := o.buildPaths(webServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it.
|
||||
func BuildOpenAPIDefinitionsForResource(model interface{}, config *common.Config) (*spec.Definitions, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
_, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
swagger, err := o.finalizeSwagger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &swagger.Definitions, nil
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the
|
||||
// passed type names.
|
||||
func BuildOpenAPIDefinitionsForResources(config *common.Config, names ...string) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
for _, name := range names {
|
||||
_, err := o.toSchema(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// newOpenAPI sets up the openAPI object so we can build the spec.
|
||||
func newOpenAPI(config *common.Config) openAPI {
|
||||
o := openAPI{
|
||||
config: config,
|
||||
swagger: &spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Swagger: OpenAPIVersion,
|
||||
Definitions: spec.Definitions{},
|
||||
Responses: config.ResponseDefinitions,
|
||||
Paths: &spec.Paths{Paths: map[string]spec.PathItem{}},
|
||||
Info: config.Info,
|
||||
},
|
||||
},
|
||||
}
|
||||
if o.config.GetOperationIDAndTags == nil {
|
||||
o.config.GetOperationIDAndTags = func(r *restful.Route) (string, []string, error) {
|
||||
return r.Operation, nil, nil
|
||||
}
|
||||
}
|
||||
if o.config.GetDefinitionName == nil {
|
||||
o.config.GetDefinitionName = func(name string) (string, spec.Extensions) {
|
||||
return name[strings.LastIndex(name, "/")+1:], nil
|
||||
}
|
||||
}
|
||||
o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return spec.MustCreateRef("#/definitions/" + common.EscapeJsonPointer(defName))
|
||||
})
|
||||
if o.config.CommonResponses == nil {
|
||||
o.config.CommonResponses = map[int]spec.Response{}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// finalizeSwagger is called after the spec is built and returns the final spec.
|
||||
// NOTE: finalizeSwagger also make changes to the final spec, as specified in the config.
|
||||
func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) {
|
||||
if o.config.SecurityDefinitions != nil {
|
||||
o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions
|
||||
o.swagger.Security = o.config.DefaultSecurity
|
||||
}
|
||||
if o.config.PostProcessSpec != nil {
|
||||
var err error
|
||||
o.swagger, err = o.config.PostProcessSpec(o.swagger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return o.swagger, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
|
||||
uniqueName, extensions := o.config.GetDefinitionName(name)
|
||||
if _, ok := o.swagger.Definitions[uniqueName]; ok {
|
||||
return nil
|
||||
}
|
||||
if item, ok := o.definitions[name]; ok {
|
||||
schema := spec.Schema{
|
||||
VendorExtensible: item.Schema.VendorExtensible,
|
||||
SchemaProps: item.Schema.SchemaProps,
|
||||
SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
|
||||
}
|
||||
if extensions != nil {
|
||||
if schema.Extensions == nil {
|
||||
schema.Extensions = spec.Extensions{}
|
||||
}
|
||||
for k, v := range extensions {
|
||||
schema.Extensions[k] = v
|
||||
}
|
||||
}
|
||||
o.swagger.Definitions[uniqueName] = schema
|
||||
for _, v := range item.Dependencies {
|
||||
if err := o.buildDefinitionRecursively(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildDefinitionForType build a definition for a given type and return a referable name to its definition.
|
||||
// This is the main function that keep track of definitions used in this spec and is depend on code generated
|
||||
// by k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen.
|
||||
func (o *openAPI) buildDefinitionForType(name string) (string, error) {
|
||||
if err := o.buildDefinitionRecursively(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return "#/definitions/" + common.EscapeJsonPointer(defName), nil
|
||||
}
|
||||
|
||||
// buildPaths builds OpenAPI paths using go-restful's web services.
|
||||
func (o *openAPI) buildPaths(webServices []*restful.WebService) error {
|
||||
pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes)
|
||||
duplicateOpId := make(map[string]string)
|
||||
for _, w := range webServices {
|
||||
rootPath := w.RootPath()
|
||||
if pathsToIgnore.HasPrefix(rootPath) {
|
||||
continue
|
||||
}
|
||||
commonParams, err := o.buildParameters(w.PathParameters())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for path, routes := range groupRoutesByPath(w.Routes()) {
|
||||
// go-swagger has special variable definition {$NAME:*} that can only be
|
||||
// used at the end of the path and it is not recognized by OpenAPI.
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
path = path[:len(path)-3] + "}"
|
||||
}
|
||||
if pathsToIgnore.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
// Aggregating common parameters make API spec (and generated clients) simpler
|
||||
inPathCommonParamsMap, err := o.findCommonParameters(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathItem, exists := o.swagger.Paths.Paths[path]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate webservice route has been found for path: %v", path)
|
||||
}
|
||||
pathItem = spec.PathItem{
|
||||
PathItemProps: spec.PathItemProps{
|
||||
Parameters: make([]spec.Parameter, 0),
|
||||
},
|
||||
}
|
||||
// add web services's parameters as well as any parameters appears in all ops, as common parameters
|
||||
pathItem.Parameters = append(pathItem.Parameters, commonParams...)
|
||||
for _, p := range inPathCommonParamsMap {
|
||||
pathItem.Parameters = append(pathItem.Parameters, p)
|
||||
}
|
||||
sortParameters(pathItem.Parameters)
|
||||
for _, route := range routes {
|
||||
op, err := o.buildOperations(route, inPathCommonParamsMap)
|
||||
sortParameters(op.Parameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dpath, exists := duplicateOpId[op.ID]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate Operation ID %v for path %v and %v", op.ID, dpath, path)
|
||||
} else {
|
||||
duplicateOpId[op.ID] = path
|
||||
}
|
||||
switch strings.ToUpper(route.Method) {
|
||||
case "GET":
|
||||
pathItem.Get = op
|
||||
case "POST":
|
||||
pathItem.Post = op
|
||||
case "HEAD":
|
||||
pathItem.Head = op
|
||||
case "PUT":
|
||||
pathItem.Put = op
|
||||
case "DELETE":
|
||||
pathItem.Delete = op
|
||||
case "OPTIONS":
|
||||
pathItem.Options = op
|
||||
case "PATCH":
|
||||
pathItem.Patch = op
|
||||
}
|
||||
}
|
||||
o.swagger.Paths.Paths[path] = pathItem
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildOperations builds operations for each webservice path
|
||||
func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map[interface{}]spec.Parameter) (ret *spec.Operation, err error) {
|
||||
ret = &spec.Operation{
|
||||
OperationProps: spec.OperationProps{
|
||||
Description: route.Doc,
|
||||
Consumes: route.Consumes,
|
||||
Produces: route.Produces,
|
||||
Schemes: o.config.ProtocolList,
|
||||
Responses: &spec.Responses{
|
||||
ResponsesProps: spec.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]spec.Response),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range route.Metadata {
|
||||
if strings.HasPrefix(k, extensionPrefix) {
|
||||
if ret.Extensions == nil {
|
||||
ret.Extensions = spec.Extensions{}
|
||||
}
|
||||
ret.Extensions.Add(k, v)
|
||||
}
|
||||
}
|
||||
if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTags(&route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Build responses
|
||||
for _, resp := range route.ResponseErrors {
|
||||
ret.Responses.StatusCodeResponses[resp.Code], err = o.buildResponse(resp.Model, resp.Message)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
// If there is no response but a write sample, assume that write sample is an http.StatusOK response.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 && route.WriteSample != nil {
|
||||
ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.WriteSample, "OK")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
for code, resp := range o.config.CommonResponses {
|
||||
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
|
||||
ret.Responses.StatusCodeResponses[code] = resp
|
||||
}
|
||||
}
|
||||
// If there is still no response, use default response provided.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 {
|
||||
ret.Responses.Default = o.config.DefaultResponse
|
||||
}
|
||||
|
||||
// Build non-common Parameters
|
||||
ret.Parameters = make([]spec.Parameter, 0)
|
||||
for _, param := range route.ParameterDocs {
|
||||
if _, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]; !isCommon {
|
||||
openAPIParam, err := o.buildParameter(param.Data(), route.ReadSample)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
ret.Parameters = append(ret.Parameters, openAPIParam)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildResponse(model interface{}, description string) (spec.Response, error) {
|
||||
schema, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return spec.Response{}, err
|
||||
}
|
||||
return spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: description,
|
||||
Schema: schema,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) findCommonParameters(routes []restful.Route) (map[interface{}]spec.Parameter, error) {
|
||||
commonParamsMap := make(map[interface{}]spec.Parameter, 0)
|
||||
paramOpsCountByName := make(map[interface{}]int, 0)
|
||||
paramNameKindToDataMap := make(map[interface{}]restful.ParameterData, 0)
|
||||
for _, route := range routes {
|
||||
routeParamDuplicateMap := make(map[interface{}]bool)
|
||||
s := ""
|
||||
for _, param := range route.ParameterDocs {
|
||||
m, _ := json.Marshal(param.Data())
|
||||
s += string(m) + "\n"
|
||||
key := mapKeyFromParam(param)
|
||||
if routeParamDuplicateMap[key] {
|
||||
msg, _ := json.Marshal(route.ParameterDocs)
|
||||
return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Data().Name, string(msg), s)
|
||||
}
|
||||
routeParamDuplicateMap[key] = true
|
||||
paramOpsCountByName[key]++
|
||||
paramNameKindToDataMap[key] = param.Data()
|
||||
}
|
||||
}
|
||||
for key, count := range paramOpsCountByName {
|
||||
paramData := paramNameKindToDataMap[key]
|
||||
if count == len(routes) && paramData.Kind != restful.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(paramData, nil)
|
||||
if err != nil {
|
||||
return commonParamsMap, err
|
||||
}
|
||||
commonParamsMap[key] = openAPIParam
|
||||
}
|
||||
}
|
||||
return commonParamsMap, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) toSchema(name string) (_ *spec.Schema, err error) {
|
||||
if openAPIType, openAPIFormat := common.GetOpenAPITypeFormat(name); openAPIType != "" {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
ref, err := o.buildDefinitionForType(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameter(restParam restful.ParameterData, bodySample interface{}) (ret spec.Parameter, err error) {
|
||||
ret = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: restParam.Name,
|
||||
Description: restParam.Description,
|
||||
Required: restParam.Required,
|
||||
},
|
||||
}
|
||||
switch restParam.Kind {
|
||||
case restful.BodyParameterKind:
|
||||
if bodySample != nil {
|
||||
ret.In = "body"
|
||||
ret.Schema, err = o.toSchema(util.GetCanonicalTypeName(bodySample))
|
||||
return ret, err
|
||||
} else {
|
||||
// There is not enough information in the body parameter to build the definition.
|
||||
// Body parameter has a data type that is a short name but we need full package name
|
||||
// of the type to create a definition.
|
||||
return ret, fmt.Errorf("restful body parameters are not supported: %v", restParam.DataType)
|
||||
}
|
||||
case restful.PathParameterKind:
|
||||
ret.In = "path"
|
||||
if !restParam.Required {
|
||||
return ret, fmt.Errorf("path parameters should be marked at required for parameter %v", restParam)
|
||||
}
|
||||
case restful.QueryParameterKind:
|
||||
ret.In = "query"
|
||||
case restful.HeaderParameterKind:
|
||||
ret.In = "header"
|
||||
case restful.FormParameterKind:
|
||||
ret.In = "formData"
|
||||
default:
|
||||
return ret, fmt.Errorf("unknown restful operation kind : %v", restParam.Kind)
|
||||
}
|
||||
openAPIType, openAPIFormat := common.GetOpenAPITypeFormat(restParam.DataType)
|
||||
if openAPIType == "" {
|
||||
return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType)
|
||||
}
|
||||
ret.Type = openAPIType
|
||||
ret.Format = openAPIFormat
|
||||
ret.UniqueItems = !restParam.AllowMultiple
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameters(restParam []*restful.Parameter) (ret []spec.Parameter, err error) {
|
||||
ret = make([]spec.Parameter, len(restParam))
|
||||
for i, v := range restParam {
|
||||
ret[i], err = o.buildParameter(v.Data(), nil)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
475
vendor/k8s.io/kube-openapi/pkg/builder/openapi_test.go
generated
vendored
475
vendor/k8s.io/kube-openapi/pkg/builder/openapi_test.go
generated
vendored
@@ -1,475 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 builder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/stretchr/testify/assert"
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// setUp is a convenience function for setting up for (most) tests.
|
||||
func setUp(t *testing.T, fullMethods bool) (*openapi.Config, *restful.Container, *assert.Assertions) {
|
||||
assert := assert.New(t)
|
||||
config, container := getConfig(fullMethods)
|
||||
return config, container, assert
|
||||
}
|
||||
|
||||
func noOp(request *restful.Request, response *restful.Response) {}
|
||||
|
||||
// Test input
|
||||
type TestInput struct {
|
||||
// Name of the input
|
||||
Name string `json:"name,omitempty"`
|
||||
// ID of the input
|
||||
ID int `json:"id,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// Test output
|
||||
type TestOutput struct {
|
||||
// Name of the output
|
||||
Name string `json:"name,omitempty"`
|
||||
// Number of outputs
|
||||
Count int `json:"count,omitempty"`
|
||||
}
|
||||
|
||||
func (_ TestInput) OpenAPIDefinition() *openapi.OpenAPIDefinition {
|
||||
schema := spec.Schema{}
|
||||
schema.Description = "Test input"
|
||||
schema.Properties = map[string]spec.Schema{
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name of the input",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"id": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ID of the input",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"tags": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
schema.Extensions = spec.Extensions{"x-test": "test"}
|
||||
return &openapi.OpenAPIDefinition{
|
||||
Schema: schema,
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func (_ TestOutput) OpenAPIDefinition() *openapi.OpenAPIDefinition {
|
||||
schema := spec.Schema{}
|
||||
schema.Description = "Test output"
|
||||
schema.Properties = map[string]spec.Schema{
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name of the output",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"count": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Number of outputs",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
}
|
||||
return &openapi.OpenAPIDefinition{
|
||||
Schema: schema,
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
var _ openapi.OpenAPIDefinitionGetter = TestInput{}
|
||||
var _ openapi.OpenAPIDefinitionGetter = TestOutput{}
|
||||
|
||||
func getTestRoute(ws *restful.WebService, method string, additionalParams bool, opPrefix string) *restful.RouteBuilder {
|
||||
ret := ws.Method(method).
|
||||
Path("/test/{path:*}").
|
||||
Doc(fmt.Sprintf("%s test input", method)).
|
||||
Operation(fmt.Sprintf("%s%sTestInput", method, opPrefix)).
|
||||
Produces(restful.MIME_JSON).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Param(ws.PathParameter("path", "path to the resource").DataType("string")).
|
||||
Param(ws.QueryParameter("pretty", "If 'true', then the output is pretty printed.")).
|
||||
Reads(TestInput{}).
|
||||
Returns(200, "OK", TestOutput{}).
|
||||
Writes(TestOutput{}).
|
||||
To(noOp)
|
||||
if additionalParams {
|
||||
ret.Param(ws.HeaderParameter("hparam", "a test head parameter").DataType("integer"))
|
||||
ret.Param(ws.FormParameter("fparam", "a test form parameter").DataType("number"))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getConfig(fullMethods bool) (*openapi.Config, *restful.Container) {
|
||||
mux := http.NewServeMux()
|
||||
container := restful.NewContainer()
|
||||
container.ServeMux = mux
|
||||
ws := new(restful.WebService)
|
||||
ws.Path("/foo")
|
||||
ws.Route(getTestRoute(ws, "get", true, "foo"))
|
||||
if fullMethods {
|
||||
ws.Route(getTestRoute(ws, "post", false, "foo")).
|
||||
Route(getTestRoute(ws, "put", false, "foo")).
|
||||
Route(getTestRoute(ws, "head", false, "foo")).
|
||||
Route(getTestRoute(ws, "patch", false, "foo")).
|
||||
Route(getTestRoute(ws, "options", false, "foo")).
|
||||
Route(getTestRoute(ws, "delete", false, "foo"))
|
||||
|
||||
}
|
||||
ws.Path("/bar")
|
||||
ws.Route(getTestRoute(ws, "get", true, "bar"))
|
||||
if fullMethods {
|
||||
ws.Route(getTestRoute(ws, "post", false, "bar")).
|
||||
Route(getTestRoute(ws, "put", false, "bar")).
|
||||
Route(getTestRoute(ws, "head", false, "bar")).
|
||||
Route(getTestRoute(ws, "patch", false, "bar")).
|
||||
Route(getTestRoute(ws, "options", false, "bar")).
|
||||
Route(getTestRoute(ws, "delete", false, "bar"))
|
||||
|
||||
}
|
||||
container.Add(ws)
|
||||
return &openapi.Config{
|
||||
ProtocolList: []string{"https"},
|
||||
Info: &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
Title: "TestAPI",
|
||||
Description: "Test API",
|
||||
Version: "unversioned",
|
||||
},
|
||||
},
|
||||
GetDefinitions: func(_ openapi.ReferenceCallback) map[string]openapi.OpenAPIDefinition {
|
||||
return map[string]openapi.OpenAPIDefinition{
|
||||
"k8s.io/kube-openapi/pkg/builder.TestInput": *TestInput{}.OpenAPIDefinition(),
|
||||
"k8s.io/kube-openapi/pkg/builder.TestOutput": *TestOutput{}.OpenAPIDefinition(),
|
||||
// Bazel changes the package name, this is ok for testing, but we need to fix it if it happened
|
||||
// in the main code.
|
||||
"k8s.io/kube-openapi/pkg/builder/go_default_test.TestInput": *TestInput{}.OpenAPIDefinition(),
|
||||
"k8s.io/kube-openapi/pkg/builder/go_default_test.TestOutput": *TestOutput{}.OpenAPIDefinition(),
|
||||
}
|
||||
},
|
||||
GetDefinitionName: func(name string) (string, spec.Extensions) {
|
||||
friendlyName := name[strings.LastIndex(name, "/")+1:]
|
||||
if strings.HasPrefix(friendlyName, "go_default_test") {
|
||||
friendlyName = "builder" + friendlyName[len("go_default_test"):]
|
||||
}
|
||||
return friendlyName, spec.Extensions{"x-test2": "test2"}
|
||||
},
|
||||
}, container
|
||||
}
|
||||
|
||||
func getTestOperation(method string, opPrefix string) *spec.Operation {
|
||||
return &spec.Operation{
|
||||
OperationProps: spec.OperationProps{
|
||||
Description: fmt.Sprintf("%s test input", method),
|
||||
Consumes: []string{"application/json"},
|
||||
Produces: []string{"application/json"},
|
||||
Schemes: []string{"https"},
|
||||
Parameters: []spec.Parameter{},
|
||||
Responses: getTestResponses(),
|
||||
ID: fmt.Sprintf("%s%sTestInput", method, opPrefix),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTestPathItem(allMethods bool, opPrefix string) spec.PathItem {
|
||||
ret := spec.PathItem{
|
||||
PathItemProps: spec.PathItemProps{
|
||||
Get: getTestOperation("get", opPrefix),
|
||||
Parameters: getTestCommonParameters(),
|
||||
},
|
||||
}
|
||||
ret.Get.Parameters = getAdditionalTestParameters()
|
||||
if allMethods {
|
||||
ret.Put = getTestOperation("put", opPrefix)
|
||||
ret.Put.Parameters = getTestParameters()
|
||||
ret.Post = getTestOperation("post", opPrefix)
|
||||
ret.Post.Parameters = getTestParameters()
|
||||
ret.Head = getTestOperation("head", opPrefix)
|
||||
ret.Head.Parameters = getTestParameters()
|
||||
ret.Patch = getTestOperation("patch", opPrefix)
|
||||
ret.Patch.Parameters = getTestParameters()
|
||||
ret.Delete = getTestOperation("delete", opPrefix)
|
||||
ret.Delete.Parameters = getTestParameters()
|
||||
ret.Options = getTestOperation("options", opPrefix)
|
||||
ret.Options.Parameters = getTestParameters()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getRefSchema(ref string) *spec.Schema {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTestResponses() *spec.Responses {
|
||||
ret := spec.Responses{
|
||||
ResponsesProps: spec.ResponsesProps{
|
||||
StatusCodeResponses: map[int]spec.Response{},
|
||||
},
|
||||
}
|
||||
ret.StatusCodeResponses[200] = spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: "OK",
|
||||
Schema: getRefSchema("#/definitions/builder.TestOutput"),
|
||||
},
|
||||
}
|
||||
return &ret
|
||||
}
|
||||
|
||||
func getTestCommonParameters() []spec.Parameter {
|
||||
ret := make([]spec.Parameter, 2)
|
||||
ret[0] = spec.Parameter{
|
||||
SimpleSchema: spec.SimpleSchema{
|
||||
Type: "string",
|
||||
},
|
||||
ParamProps: spec.ParamProps{
|
||||
Description: "path to the resource",
|
||||
Name: "path",
|
||||
In: "path",
|
||||
Required: true,
|
||||
},
|
||||
CommonValidations: spec.CommonValidations{
|
||||
UniqueItems: true,
|
||||
},
|
||||
}
|
||||
ret[1] = spec.Parameter{
|
||||
SimpleSchema: spec.SimpleSchema{
|
||||
Type: "string",
|
||||
},
|
||||
ParamProps: spec.ParamProps{
|
||||
Description: "If 'true', then the output is pretty printed.",
|
||||
Name: "pretty",
|
||||
In: "query",
|
||||
},
|
||||
CommonValidations: spec.CommonValidations{
|
||||
UniqueItems: true,
|
||||
},
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getTestParameters() []spec.Parameter {
|
||||
ret := make([]spec.Parameter, 1)
|
||||
ret[0] = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: "body",
|
||||
In: "body",
|
||||
Required: true,
|
||||
Schema: getRefSchema("#/definitions/builder.TestInput"),
|
||||
},
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getAdditionalTestParameters() []spec.Parameter {
|
||||
ret := make([]spec.Parameter, 3)
|
||||
ret[0] = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: "body",
|
||||
In: "body",
|
||||
Required: true,
|
||||
Schema: getRefSchema("#/definitions/builder.TestInput"),
|
||||
},
|
||||
}
|
||||
ret[1] = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: "fparam",
|
||||
Description: "a test form parameter",
|
||||
In: "formData",
|
||||
},
|
||||
SimpleSchema: spec.SimpleSchema{
|
||||
Type: "number",
|
||||
},
|
||||
CommonValidations: spec.CommonValidations{
|
||||
UniqueItems: true,
|
||||
},
|
||||
}
|
||||
ret[2] = spec.Parameter{
|
||||
SimpleSchema: spec.SimpleSchema{
|
||||
Type: "integer",
|
||||
},
|
||||
ParamProps: spec.ParamProps{
|
||||
Description: "a test head parameter",
|
||||
Name: "hparam",
|
||||
In: "header",
|
||||
},
|
||||
CommonValidations: spec.CommonValidations{
|
||||
UniqueItems: true,
|
||||
},
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func getTestInputDefinition() spec.Schema {
|
||||
return spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Test input",
|
||||
Properties: map[string]spec.Schema{
|
||||
"id": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "ID of the input",
|
||||
Type: spec.StringOrArray{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name of the input",
|
||||
Type: spec.StringOrArray{"string"},
|
||||
},
|
||||
},
|
||||
"tags": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: spec.StringOrArray{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: spec.StringOrArray{"string"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-test": "test",
|
||||
"x-test2": "test2",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getTestOutputDefinition() spec.Schema {
|
||||
return spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Test output",
|
||||
Properties: map[string]spec.Schema{
|
||||
"count": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Number of outputs",
|
||||
Type: spec.StringOrArray{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"name": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Name of the output",
|
||||
Type: spec.StringOrArray{"string"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-test2": "test2",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildOpenAPISpec(t *testing.T) {
|
||||
config, container, assert := setUp(t, true)
|
||||
expected := &spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Info: &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
Title: "TestAPI",
|
||||
Description: "Test API",
|
||||
Version: "unversioned",
|
||||
},
|
||||
},
|
||||
Swagger: "2.0",
|
||||
Paths: &spec.Paths{
|
||||
Paths: map[string]spec.PathItem{
|
||||
"/foo/test/{path}": getTestPathItem(true, "foo"),
|
||||
"/bar/test/{path}": getTestPathItem(true, "bar"),
|
||||
},
|
||||
},
|
||||
Definitions: spec.Definitions{
|
||||
"builder.TestInput": getTestInputDefinition(),
|
||||
"builder.TestOutput": getTestOutputDefinition(),
|
||||
},
|
||||
},
|
||||
}
|
||||
swagger, err := BuildOpenAPISpec(container.RegisteredWebServices(), config)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
expected_json, err := json.Marshal(expected)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
actual_json, err := json.Marshal(swagger)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(string(expected_json), string(actual_json))
|
||||
}
|
||||
|
||||
func TestBuildOpenAPIDefinitionsForResource(t *testing.T) {
|
||||
config, _, assert := setUp(t, true)
|
||||
expected := &spec.Definitions{
|
||||
"builder.TestInput": getTestInputDefinition(),
|
||||
}
|
||||
swagger, err := BuildOpenAPIDefinitionsForResource(TestInput{}, config)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
expected_json, err := json.Marshal(expected)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
actual_json, err := json.Marshal(swagger)
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
assert.Equal(string(expected_json), string(actual_json))
|
||||
}
|
61
vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
61
vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 builder
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
)
|
||||
|
||||
type parameters []spec.Parameter
|
||||
|
||||
func (s parameters) Len() int { return len(s) }
|
||||
func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// byNameIn used in sorting parameters by Name and In fields.
|
||||
type byNameIn struct {
|
||||
parameters
|
||||
}
|
||||
|
||||
func (s byNameIn) Less(i, j int) bool {
|
||||
return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In)
|
||||
}
|
||||
|
||||
// SortParameters sorts parameters by Name and In fields.
|
||||
func sortParameters(p []spec.Parameter) {
|
||||
sort.Sort(byNameIn{p})
|
||||
}
|
||||
|
||||
func groupRoutesByPath(routes []restful.Route) map[string][]restful.Route {
|
||||
pathToRoutes := make(map[string][]restful.Route)
|
||||
for _, r := range routes {
|
||||
pathToRoutes[r.Path] = append(pathToRoutes[r.Path], r)
|
||||
}
|
||||
return pathToRoutes
|
||||
}
|
||||
|
||||
func mapKeyFromParam(param *restful.Parameter) interface{} {
|
||||
return struct {
|
||||
Name string
|
||||
Kind int
|
||||
}{
|
||||
Name: param.Data().Name,
|
||||
Kind: param.Data().Kind,
|
||||
}
|
||||
}
|
174
vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
174
vendor/k8s.io/kube-openapi/pkg/common/common.go
generated
vendored
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 common
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
)
|
||||
|
||||
// OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi.
|
||||
type OpenAPIDefinition struct {
|
||||
Schema spec.Schema
|
||||
Dependencies []string
|
||||
}
|
||||
|
||||
type ReferenceCallback func(path string) spec.Ref
|
||||
|
||||
// GetOpenAPIDefinitions is collection of all definitions.
|
||||
type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition
|
||||
|
||||
// OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface,
|
||||
// the definition returned by it will be used, otherwise the auto-generated definitions will be used. See
|
||||
// GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when
|
||||
// possible.
|
||||
type OpenAPIDefinitionGetter interface {
|
||||
OpenAPIDefinition() *OpenAPIDefinition
|
||||
}
|
||||
|
||||
type PathHandler interface {
|
||||
Handle(path string, handler http.Handler)
|
||||
}
|
||||
|
||||
// Config is set of configuration for openAPI spec generation.
|
||||
type Config struct {
|
||||
// List of supported protocols such as https, http, etc.
|
||||
ProtocolList []string
|
||||
|
||||
// Info is general information about the API.
|
||||
Info *spec.Info
|
||||
|
||||
// DefaultResponse will be used if an operation does not have any responses listed. It
|
||||
// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec.
|
||||
DefaultResponse *spec.Response
|
||||
|
||||
// ResponseDefinitions will be added to "responses" under the top-level swagger object. This is an object
|
||||
// that holds responses definitions that can be used across operations. This property does not define
|
||||
// global responses for all operations. For more info please refer:
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields
|
||||
ResponseDefinitions map[string]spec.Response
|
||||
|
||||
// CommonResponses will be added as a response to all operation specs. This is a good place to add common
|
||||
// responses such as authorization failed.
|
||||
CommonResponses map[int]spec.Response
|
||||
|
||||
// List of webservice's path prefixes to ignore
|
||||
IgnorePrefixes []string
|
||||
|
||||
// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map
|
||||
// or any of the models will result in spec generation failure.
|
||||
GetDefinitions GetOpenAPIDefinitions
|
||||
|
||||
// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs.
|
||||
GetOperationIDAndTags func(r *restful.Route) (string, []string, error)
|
||||
|
||||
// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition.
|
||||
// It is an optional function to customize model names.
|
||||
GetDefinitionName func(name string) (string, spec.Extensions)
|
||||
|
||||
// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving.
|
||||
PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error)
|
||||
|
||||
// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config
|
||||
// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses.
|
||||
SecurityDefinitions *spec.SecurityDefinitions
|
||||
|
||||
// DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI.
|
||||
// For most cases, this will be list of acceptable definitions in SecurityDefinitions.
|
||||
DefaultSecurity []map[string][]string
|
||||
}
|
||||
|
||||
var schemaTypeFormatMap = map[string][]string{
|
||||
"uint": {"integer", "int32"},
|
||||
"uint8": {"integer", "byte"},
|
||||
"uint16": {"integer", "int32"},
|
||||
"uint32": {"integer", "int64"},
|
||||
"uint64": {"integer", "int64"},
|
||||
"int": {"integer", "int32"},
|
||||
"int8": {"integer", "byte"},
|
||||
"int16": {"integer", "int32"},
|
||||
"int32": {"integer", "int32"},
|
||||
"int64": {"integer", "int64"},
|
||||
"byte": {"integer", "byte"},
|
||||
"float64": {"number", "double"},
|
||||
"float32": {"number", "float"},
|
||||
"bool": {"boolean", ""},
|
||||
"time.Time": {"string", "date-time"},
|
||||
"string": {"string", ""},
|
||||
"integer": {"integer", ""},
|
||||
"number": {"number", ""},
|
||||
"boolean": {"boolean", ""},
|
||||
"[]byte": {"string", "byte"}, // base64 encoded characters
|
||||
"interface{}": {"object", ""},
|
||||
}
|
||||
|
||||
// This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are
|
||||
// two ways to customize spec for a type. If you add it here, a type will be converted to a simple type and the type
|
||||
// comment (the comment that is added before type definition) will be lost. The spec will still have the property
|
||||
// comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so
|
||||
// the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple
|
||||
// type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation.
|
||||
// Example:
|
||||
// type Sample struct {
|
||||
// ...
|
||||
// // port of the server
|
||||
// port IntOrString
|
||||
// ...
|
||||
// }
|
||||
// // IntOrString documentation...
|
||||
// type IntOrString { ... }
|
||||
//
|
||||
// Adding IntOrString to this function:
|
||||
// "port" : {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
//
|
||||
// Implement OpenAPIDefinitionGetter for IntOrString:
|
||||
//
|
||||
// "port" : {
|
||||
// $Ref: "#/definitions/IntOrString"
|
||||
// Description: "port of the server"
|
||||
// }
|
||||
// ...
|
||||
// definitions:
|
||||
// {
|
||||
// "IntOrString": {
|
||||
// format: "string",
|
||||
// type: "int-or-string",
|
||||
// Description: "IntOrString documentation..." // new
|
||||
// }
|
||||
// }
|
||||
//
|
||||
func GetOpenAPITypeFormat(typeName string) (string, string) {
|
||||
mapped, ok := schemaTypeFormatMap[typeName]
|
||||
if !ok {
|
||||
return "", ""
|
||||
}
|
||||
return mapped[0], mapped[1]
|
||||
}
|
||||
|
||||
func EscapeJsonPointer(p string) string {
|
||||
// Escaping reference name using rfc6901
|
||||
p = strings.Replace(p, "~", "~0", -1)
|
||||
p = strings.Replace(p, "/", "~1", -1)
|
||||
return p
|
||||
}
|
19
vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
19
vendor/k8s.io/kube-openapi/pkg/common/doc.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 common holds shared code and types between open API code
|
||||
// generator and spec generator.
|
||||
package common
|
49
vendor/k8s.io/kube-openapi/pkg/generators/README.md
generated
vendored
49
vendor/k8s.io/kube-openapi/pkg/generators/README.md
generated
vendored
@@ -1,49 +0,0 @@
|
||||
# Generate OpenAPI definitions
|
||||
|
||||
- To generate definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines.
|
||||
- To exclude a type or a member from a tagged package/type, add "+k8s:openapi-gen=false" tag to the comment lines.
|
||||
|
||||
# OpenAPI Extensions
|
||||
|
||||
OpenAPI spec can have extensions on types. To define one or more extensions on a type or its member
|
||||
add `+k8s:openapi-gen=x-kubernetes-$NAME:$VALUE` to the comment lines before type/member. A type/member can
|
||||
have multiple extensions. The rest of the line in the comment will be used as $VALUE so there is no need to
|
||||
escape or quote the value string. Extensions can be used to pass more information to client generators or
|
||||
documentation generators. For example a type might have a friendly name to be displayed in documentation or
|
||||
being used in a client's fluent interface.
|
||||
|
||||
# Custom OpenAPI type definitions
|
||||
|
||||
Custom types which otherwise don't map directly to OpenAPI can override their
|
||||
OpenAPI definition by implementing a function named "OpenAPIDefinition" with
|
||||
the following signature:
|
||||
|
||||
```go
|
||||
import openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
// ...
|
||||
|
||||
type Time struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (_ Time) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "date-time",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, the type can avoid the "openapi" import by defining the following
|
||||
methods. The following example produces the same OpenAPI definition as the
|
||||
example above:
|
||||
|
||||
```go
|
||||
func (_ Time) OpenAPISchemaType() []string { return []string{"string"} }
|
||||
func (_ Time) OpenAPISchemaFormat() string { return "date-time" }
|
||||
```
|
219
vendor/k8s.io/kube-openapi/pkg/generators/api_linter.go
generated
vendored
219
vendor/k8s.io/kube-openapi/pkg/generators/api_linter.go
generated
vendored
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/generators/rules"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const apiViolationFileType = "api-violation"
|
||||
|
||||
type apiViolationFile struct {
|
||||
// Since our file actually is unrelated to the package structure, use a
|
||||
// path that hasn't been mangled by the framework.
|
||||
unmangledPath string
|
||||
}
|
||||
|
||||
func (a apiViolationFile) AssembleFile(f *generator.File, path string) error {
|
||||
path = a.unmangledPath
|
||||
klog.V(2).Infof("Assembling file %q", path)
|
||||
if path == "-" {
|
||||
_, err := io.Copy(os.Stdout, &f.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
output, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output.Close()
|
||||
_, err = io.Copy(output, &f.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a apiViolationFile) VerifyFile(f *generator.File, path string) error {
|
||||
if path == "-" {
|
||||
// Nothing to verify against.
|
||||
return nil
|
||||
}
|
||||
path = a.unmangledPath
|
||||
|
||||
formatted := f.Body.Bytes()
|
||||
existing, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read file %q for comparison: %v", path, err)
|
||||
}
|
||||
if bytes.Compare(formatted, existing) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Be nice and find the first place where they differ
|
||||
// (Copied from gengo's default file type)
|
||||
i := 0
|
||||
for i < len(formatted) && i < len(existing) && formatted[i] == existing[i] {
|
||||
i++
|
||||
}
|
||||
eDiff, fDiff := existing[i:], formatted[i:]
|
||||
if len(eDiff) > 100 {
|
||||
eDiff = eDiff[:100]
|
||||
}
|
||||
if len(fDiff) > 100 {
|
||||
fDiff = fDiff[:100]
|
||||
}
|
||||
return fmt.Errorf("output for %q differs; first existing/expected diff: \n %q\n %q", path, string(eDiff), string(fDiff))
|
||||
}
|
||||
|
||||
func newAPIViolationGen() *apiViolationGen {
|
||||
return &apiViolationGen{
|
||||
linter: newAPILinter(),
|
||||
}
|
||||
}
|
||||
|
||||
type apiViolationGen struct {
|
||||
generator.DefaultGen
|
||||
|
||||
linter *apiLinter
|
||||
}
|
||||
|
||||
func (v *apiViolationGen) FileType() string { return apiViolationFileType }
|
||||
func (v *apiViolationGen) Filename() string {
|
||||
return "this file is ignored by the file assembler"
|
||||
}
|
||||
|
||||
func (v *apiViolationGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
klog.V(5).Infof("validating API rules for type %v", t)
|
||||
if err := v.linter.validate(t); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Finalize prints the API rule violations to report file (if specified from
|
||||
// arguments) or stdout (default)
|
||||
func (v *apiViolationGen) Finalize(c *generator.Context, w io.Writer) error {
|
||||
// NOTE: we don't return error here because we assume that the report file will
|
||||
// get evaluated afterwards to determine if error should be raised. For example,
|
||||
// you can have make rules that compare the report file with existing known
|
||||
// violations (whitelist) and determine no error if no change is detected.
|
||||
v.linter.report(w)
|
||||
return nil
|
||||
}
|
||||
|
||||
// apiLinter is the framework hosting multiple API rules and recording API rule
|
||||
// violations
|
||||
type apiLinter struct {
|
||||
// API rules that implement APIRule interface and output API rule violations
|
||||
rules []APIRule
|
||||
violations []apiViolation
|
||||
}
|
||||
|
||||
// newAPILinter creates an apiLinter object with API rules in package rules. Please
|
||||
// add APIRule here when new API rule is implemented.
|
||||
func newAPILinter() *apiLinter {
|
||||
return &apiLinter{
|
||||
rules: []APIRule{
|
||||
&rules.NamesMatch{},
|
||||
&rules.OmitEmptyMatchCase{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// apiViolation uniquely identifies single API rule violation
|
||||
type apiViolation struct {
|
||||
// Name of rule from APIRule.Name()
|
||||
rule string
|
||||
|
||||
packageName string
|
||||
typeName string
|
||||
|
||||
// Optional: name of field that violates API rule. Empty fieldName implies that
|
||||
// the entire type violates the rule.
|
||||
field string
|
||||
}
|
||||
|
||||
// apiViolations implements sort.Interface for []apiViolation based on the fields: rule,
|
||||
// packageName, typeName and field.
|
||||
type apiViolations []apiViolation
|
||||
|
||||
func (a apiViolations) Len() int { return len(a) }
|
||||
func (a apiViolations) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a apiViolations) Less(i, j int) bool {
|
||||
if a[i].rule != a[j].rule {
|
||||
return a[i].rule < a[j].rule
|
||||
}
|
||||
if a[i].packageName != a[j].packageName {
|
||||
return a[i].packageName < a[j].packageName
|
||||
}
|
||||
if a[i].typeName != a[j].typeName {
|
||||
return a[i].typeName < a[j].typeName
|
||||
}
|
||||
return a[i].field < a[j].field
|
||||
}
|
||||
|
||||
// APIRule is the interface for validating API rule on Go types
|
||||
type APIRule interface {
|
||||
// Validate evaluates API rule on type t and returns a list of field names in
|
||||
// the type that violate the rule. Empty field name [""] implies the entire
|
||||
// type violates the rule.
|
||||
Validate(t *types.Type) ([]string, error)
|
||||
|
||||
// Name returns the name of APIRule
|
||||
Name() string
|
||||
}
|
||||
|
||||
// validate runs all API rules on type t and records any API rule violation
|
||||
func (l *apiLinter) validate(t *types.Type) error {
|
||||
for _, r := range l.rules {
|
||||
klog.V(5).Infof("validating API rule %v for type %v", r.Name(), t)
|
||||
fields, err := r.Validate(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, field := range fields {
|
||||
l.violations = append(l.violations, apiViolation{
|
||||
rule: r.Name(),
|
||||
packageName: t.Name.Package,
|
||||
typeName: t.Name.Name,
|
||||
field: field,
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// report prints any API rule violation to writer w and returns error if violation exists
|
||||
func (l *apiLinter) report(w io.Writer) error {
|
||||
sort.Sort(apiViolations(l.violations))
|
||||
for _, v := range l.violations {
|
||||
fmt.Fprintf(w, "API rule violation: %s,%s,%s,%s\n", v.rule, v.packageName, v.typeName, v.field)
|
||||
}
|
||||
if len(l.violations) > 0 {
|
||||
return fmt.Errorf("API rule violations exist")
|
||||
}
|
||||
return nil
|
||||
}
|
91
vendor/k8s.io/kube-openapi/pkg/generators/config.go
generated
vendored
91
vendor/k8s.io/kube-openapi/pkg/generators/config.go
generated
vendored
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
"k8s.io/klog"
|
||||
|
||||
generatorargs "k8s.io/kube-openapi/cmd/openapi-gen/args"
|
||||
)
|
||||
|
||||
type identityNamer struct{}
|
||||
|
||||
func (_ identityNamer) Name(t *types.Type) string {
|
||||
return t.Name.String()
|
||||
}
|
||||
|
||||
var _ namer.Namer = identityNamer{}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
"sorting_namer": identityNamer{},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "sorting_namer"
|
||||
}
|
||||
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
header = append(header, []byte(
|
||||
`
|
||||
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||
|
||||
`)...)
|
||||
|
||||
reportPath := "-"
|
||||
if customArgs, ok := arguments.CustomArgs.(*generatorargs.CustomArgs); ok {
|
||||
reportPath = customArgs.ReportFilename
|
||||
}
|
||||
context.FileTypes[apiViolationFileType] = apiViolationFile{
|
||||
unmangledPath: reportPath,
|
||||
}
|
||||
|
||||
return generator.Packages{
|
||||
&generator.DefaultPackage{
|
||||
PackageName: filepath.Base(arguments.OutputPackagePath),
|
||||
PackagePath: arguments.OutputPackagePath,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
newOpenAPIGen(
|
||||
arguments.OutputFileBaseName,
|
||||
arguments.OutputPackagePath,
|
||||
),
|
||||
newAPIViolationGen(),
|
||||
}
|
||||
},
|
||||
FilterFunc: apiTypeFilterFunc,
|
||||
},
|
||||
}
|
||||
}
|
182
vendor/k8s.io/kube-openapi/pkg/generators/extension.go
generated
vendored
182
vendor/k8s.io/kube-openapi/pkg/generators/extension.go
generated
vendored
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 generators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
const extensionPrefix = "x-kubernetes-"
|
||||
|
||||
// extensionAttributes encapsulates common traits for particular extensions.
|
||||
type extensionAttributes struct {
|
||||
xName string
|
||||
kind types.Kind
|
||||
allowedValues sets.String
|
||||
}
|
||||
|
||||
// Extension tag to openapi extension attributes
|
||||
var tagToExtension = map[string]extensionAttributes{
|
||||
"patchMergeKey": {
|
||||
xName: "x-kubernetes-patch-merge-key",
|
||||
kind: types.Slice,
|
||||
},
|
||||
"patchStrategy": {
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
kind: types.Slice,
|
||||
allowedValues: sets.NewString("merge", "retainKeys"),
|
||||
},
|
||||
"listMapKey": {
|
||||
xName: "x-kubernetes-list-map-keys",
|
||||
kind: types.Slice,
|
||||
},
|
||||
"listType": {
|
||||
xName: "x-kubernetes-list-type",
|
||||
kind: types.Slice,
|
||||
allowedValues: sets.NewString("atomic", "set", "map"),
|
||||
},
|
||||
}
|
||||
|
||||
// Extension encapsulates information necessary to generate an OpenAPI extension.
|
||||
type extension struct {
|
||||
idlTag string // Example: listType
|
||||
xName string // Example: x-kubernetes-list-type
|
||||
values []string // Example: [atomic]
|
||||
}
|
||||
|
||||
func (e extension) hasAllowedValues() bool {
|
||||
return tagToExtension[e.idlTag].allowedValues.Len() > 0
|
||||
}
|
||||
|
||||
func (e extension) allowedValues() sets.String {
|
||||
return tagToExtension[e.idlTag].allowedValues
|
||||
}
|
||||
|
||||
func (e extension) hasKind() bool {
|
||||
return len(tagToExtension[e.idlTag].kind) > 0
|
||||
}
|
||||
|
||||
func (e extension) kind() types.Kind {
|
||||
return tagToExtension[e.idlTag].kind
|
||||
}
|
||||
|
||||
func (e extension) validateAllowedValues() error {
|
||||
// allowedValues not set means no restrictions on values.
|
||||
if !e.hasAllowedValues() {
|
||||
return nil
|
||||
}
|
||||
// Check for missing value.
|
||||
if len(e.values) == 0 {
|
||||
return fmt.Errorf("%s needs a value, none given.", e.idlTag)
|
||||
}
|
||||
// For each extension value, validate that it is allowed.
|
||||
allowedValues := e.allowedValues()
|
||||
if !allowedValues.HasAll(e.values...) {
|
||||
return fmt.Errorf("%v not allowed for %s. Allowed values: %v",
|
||||
e.values, e.idlTag, allowedValues.List())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e extension) validateType(kind types.Kind) error {
|
||||
// If this extension class has no kind, then don't validate the type.
|
||||
if !e.hasKind() {
|
||||
return nil
|
||||
}
|
||||
if kind != e.kind() {
|
||||
return fmt.Errorf("tag %s on type %v; only allowed on type %v",
|
||||
e.idlTag, kind, e.kind())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e extension) hasMultipleValues() bool {
|
||||
return len(e.values) > 1
|
||||
}
|
||||
|
||||
// Returns sorted list of map keys. Needed for deterministic testing.
|
||||
func sortedMapKeys(m map[string][]string) []string {
|
||||
keys := make([]string, len(m))
|
||||
i := 0
|
||||
for k := range m {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Parses comments to return openapi extensions. Returns a list of
|
||||
// extensions which parsed correctly, as well as a list of the
|
||||
// parse errors. Validating extensions is performed separately.
|
||||
// NOTE: Non-empty errors does not mean extensions is empty.
|
||||
func parseExtensions(comments []string) ([]extension, []error) {
|
||||
extensions := []extension{}
|
||||
errors := []error{}
|
||||
// First, generate extensions from "+k8s:openapi-gen=x-kubernetes-*" annotations.
|
||||
values := getOpenAPITagValue(comments)
|
||||
for _, val := range values {
|
||||
// Example: x-kubernetes-member-tag:member_test
|
||||
if strings.HasPrefix(val, extensionPrefix) {
|
||||
parts := strings.SplitN(val, ":", 2)
|
||||
if len(parts) != 2 {
|
||||
errors = append(errors, fmt.Errorf("invalid extension value: %v", val))
|
||||
continue
|
||||
}
|
||||
e := extension{
|
||||
idlTag: tagName, // Example: k8s:openapi-gen
|
||||
xName: parts[0], // Example: x-kubernetes-member-tag
|
||||
values: []string{parts[1]}, // Example: member_test
|
||||
}
|
||||
extensions = append(extensions, e)
|
||||
}
|
||||
}
|
||||
// Next, generate extensions from "idlTags" (e.g. +listType)
|
||||
tagValues := types.ExtractCommentTags("+", comments)
|
||||
for _, idlTag := range sortedMapKeys(tagValues) {
|
||||
xAttrs, exists := tagToExtension[idlTag]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
values := tagValues[idlTag]
|
||||
e := extension{
|
||||
idlTag: idlTag, // listType
|
||||
xName: xAttrs.xName, // x-kubernetes-list-type
|
||||
values: values, // [atomic]
|
||||
}
|
||||
extensions = append(extensions, e)
|
||||
}
|
||||
return extensions, errors
|
||||
}
|
||||
|
||||
func validateMemberExtensions(extensions []extension, m *types.Member) []error {
|
||||
errors := []error{}
|
||||
for _, e := range extensions {
|
||||
if err := e.validateAllowedValues(); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
if err := e.validateType(m.Type.Kind); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
454
vendor/k8s.io/kube-openapi/pkg/generators/extension_test.go
generated
vendored
454
vendor/k8s.io/kube-openapi/pkg/generators/extension_test.go
generated
vendored
@@ -1,454 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 generators
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
func TestSingleTagExtension(t *testing.T) {
|
||||
|
||||
// Comments only contain one tag extension and one value.
|
||||
var tests = []struct {
|
||||
comments []string
|
||||
extensionTag string
|
||||
extensionName string
|
||||
extensionValues []string
|
||||
}{
|
||||
{
|
||||
comments: []string{"+patchMergeKey=name"},
|
||||
extensionTag: "patchMergeKey",
|
||||
extensionName: "x-kubernetes-patch-merge-key",
|
||||
extensionValues: []string{"name"},
|
||||
},
|
||||
{
|
||||
comments: []string{"+patchStrategy=merge"},
|
||||
extensionTag: "patchStrategy",
|
||||
extensionName: "x-kubernetes-patch-strategy",
|
||||
extensionValues: []string{"merge"},
|
||||
},
|
||||
{
|
||||
comments: []string{"+listType=atomic"},
|
||||
extensionTag: "listType",
|
||||
extensionName: "x-kubernetes-list-type",
|
||||
extensionValues: []string{"atomic"},
|
||||
},
|
||||
{
|
||||
comments: []string{"+listMapKey=port"},
|
||||
extensionTag: "listMapKey",
|
||||
extensionName: "x-kubernetes-list-map-keys",
|
||||
extensionValues: []string{"port"},
|
||||
},
|
||||
{
|
||||
comments: []string{"+k8s:openapi-gen=x-kubernetes-member-tag:member_test"},
|
||||
extensionTag: "k8s:openapi-gen",
|
||||
extensionName: "x-kubernetes-member-tag",
|
||||
extensionValues: []string{"member_test"},
|
||||
},
|
||||
{
|
||||
comments: []string{"+k8s:openapi-gen=x-kubernetes-member-tag:member_test:member_test2"},
|
||||
extensionTag: "k8s:openapi-gen",
|
||||
extensionName: "x-kubernetes-member-tag",
|
||||
extensionValues: []string{"member_test:member_test2"},
|
||||
},
|
||||
{
|
||||
// Test that poorly formatted extensions aren't added.
|
||||
comments: []string{
|
||||
"+k8s:openapi-gen=x-kubernetes-no-value",
|
||||
"+k8s:openapi-gen=x-kubernetes-member-success:success",
|
||||
"+k8s:openapi-gen=x-kubernetes-wrong-separator;error",
|
||||
},
|
||||
extensionTag: "k8s:openapi-gen",
|
||||
extensionName: "x-kubernetes-member-success",
|
||||
extensionValues: []string{"success"},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
extensions, _ := parseExtensions(test.comments)
|
||||
actual := extensions[0]
|
||||
if actual.idlTag != test.extensionTag {
|
||||
t.Errorf("Extension Tag: expected (%s), actual (%s)\n", test.extensionTag, actual.idlTag)
|
||||
}
|
||||
if actual.xName != test.extensionName {
|
||||
t.Errorf("Extension Name: expected (%s), actual (%s)\n", test.extensionName, actual.xName)
|
||||
}
|
||||
if !reflect.DeepEqual(actual.values, test.extensionValues) {
|
||||
t.Errorf("Extension Values: expected (%s), actual (%s)\n", test.extensionValues, actual.values)
|
||||
}
|
||||
if actual.hasMultipleValues() {
|
||||
t.Errorf("%s: hasMultipleValues() should be false\n", actual.xName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMultipleTagExtensions(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
comments []string
|
||||
extensionTag string
|
||||
extensionName string
|
||||
extensionValues []string
|
||||
}{
|
||||
{
|
||||
comments: []string{
|
||||
"+listMapKey=port",
|
||||
"+listMapKey=protocol",
|
||||
},
|
||||
extensionTag: "listMapKey",
|
||||
extensionName: "x-kubernetes-list-map-keys",
|
||||
extensionValues: []string{"port", "protocol"},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
extensions, errors := parseExtensions(test.comments)
|
||||
if len(errors) > 0 {
|
||||
t.Errorf("Unexpected errors: %v\n", errors)
|
||||
}
|
||||
actual := extensions[0]
|
||||
if actual.idlTag != test.extensionTag {
|
||||
t.Errorf("Extension Tag: expected (%s), actual (%s)\n", test.extensionTag, actual.idlTag)
|
||||
}
|
||||
if actual.xName != test.extensionName {
|
||||
t.Errorf("Extension Name: expected (%s), actual (%s)\n", test.extensionName, actual.xName)
|
||||
}
|
||||
if !reflect.DeepEqual(actual.values, test.extensionValues) {
|
||||
t.Errorf("Extension Values: expected (%s), actual (%s)\n", test.extensionValues, actual.values)
|
||||
}
|
||||
if !actual.hasMultipleValues() {
|
||||
t.Errorf("%s: hasMultipleValues() should be true\n", actual.xName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtensionParseErrors(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
comments []string
|
||||
errorMessage string
|
||||
}{
|
||||
{
|
||||
// Missing extension value should be an error.
|
||||
comments: []string{
|
||||
"+k8s:openapi-gen=x-kubernetes-no-value",
|
||||
},
|
||||
errorMessage: "x-kubernetes-no-value",
|
||||
},
|
||||
{
|
||||
// Wrong separator should be an error.
|
||||
comments: []string{
|
||||
"+k8s:openapi-gen=x-kubernetes-wrong-separator;error",
|
||||
},
|
||||
errorMessage: "x-kubernetes-wrong-separator;error",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
_, errors := parseExtensions(test.comments)
|
||||
if len(errors) == 0 {
|
||||
t.Errorf("Expected errors while parsing: %v\n", test.comments)
|
||||
}
|
||||
error := errors[0]
|
||||
if !strings.Contains(error.Error(), test.errorMessage) {
|
||||
t.Errorf("Error (%v) should contain substring (%s)\n", error, test.errorMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtensionAllowedValues(t *testing.T) {
|
||||
|
||||
var methodTests = []struct {
|
||||
e extension
|
||||
allowedValues sets.String
|
||||
}{
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
},
|
||||
allowedValues: sets.NewString("merge", "retainKeys"),
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchMergeKey",
|
||||
},
|
||||
allowedValues: nil,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listType",
|
||||
},
|
||||
allowedValues: sets.NewString("atomic", "set", "map"),
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listMapKey",
|
||||
},
|
||||
allowedValues: nil,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "k8s:openapi-gen",
|
||||
},
|
||||
allowedValues: nil,
|
||||
},
|
||||
}
|
||||
for _, test := range methodTests {
|
||||
if test.allowedValues != nil {
|
||||
if !test.e.hasAllowedValues() {
|
||||
t.Errorf("hasAllowedValues() expected (true), but received: false")
|
||||
}
|
||||
if !reflect.DeepEqual(test.allowedValues, test.e.allowedValues()) {
|
||||
t.Errorf("allowedValues() expected (%v), but received: %v",
|
||||
test.allowedValues, test.e.allowedValues())
|
||||
}
|
||||
}
|
||||
if test.allowedValues == nil && test.e.hasAllowedValues() {
|
||||
t.Errorf("hasAllowedValues() expected (false), but received: true")
|
||||
}
|
||||
}
|
||||
|
||||
var successTests = []struct {
|
||||
e extension
|
||||
}{
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
values: []string{"merge"},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Validate multiple values.
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
values: []string{"merge", "retainKeys"},
|
||||
},
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchMergeKey",
|
||||
xName: "x-kubernetes-patch-merge-key",
|
||||
values: []string{"key1"},
|
||||
},
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listType",
|
||||
xName: "x-kubernetes-list-type",
|
||||
values: []string{"atomic"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range successTests {
|
||||
actualErr := test.e.validateAllowedValues()
|
||||
if actualErr != nil {
|
||||
t.Errorf("Expected no error for (%v), but received: %v\n", test.e, actualErr)
|
||||
}
|
||||
}
|
||||
|
||||
var failureTests = []struct {
|
||||
e extension
|
||||
}{
|
||||
{
|
||||
// Every value must be allowed.
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
values: []string{"disallowed", "merge"},
|
||||
},
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
values: []string{"foo"},
|
||||
},
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listType",
|
||||
xName: "x-kubernetes-list-type",
|
||||
values: []string{"not-allowed"},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range failureTests {
|
||||
actualErr := test.e.validateAllowedValues()
|
||||
if actualErr == nil {
|
||||
t.Errorf("Expected error, but received none: %v\n", test.e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestExtensionKind(t *testing.T) {
|
||||
|
||||
var methodTests = []struct {
|
||||
e extension
|
||||
kind types.Kind
|
||||
}{
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchStrategy",
|
||||
},
|
||||
kind: types.Slice,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "patchMergeKey",
|
||||
},
|
||||
kind: types.Slice,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listType",
|
||||
},
|
||||
kind: types.Slice,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "listMapKey",
|
||||
},
|
||||
kind: types.Slice,
|
||||
},
|
||||
{
|
||||
e: extension{
|
||||
idlTag: "k8s:openapi-gen",
|
||||
},
|
||||
kind: "",
|
||||
},
|
||||
}
|
||||
for _, test := range methodTests {
|
||||
if len(test.kind) > 0 {
|
||||
if !test.e.hasKind() {
|
||||
t.Errorf("%v: hasKind() expected (true), but received: false", test.e)
|
||||
}
|
||||
if test.kind != test.e.kind() {
|
||||
t.Errorf("%v: kind() expected (%v), but received: %v", test.e, test.kind, test.e.kind())
|
||||
}
|
||||
} else {
|
||||
if test.e.hasKind() {
|
||||
t.Errorf("%v: hasKind() expected (false), but received: true", test.e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMemberExtensions(t *testing.T) {
|
||||
|
||||
patchStrategyExtension := extension{
|
||||
idlTag: "patchStrategy",
|
||||
xName: "x-kubernetes-patch-strategy",
|
||||
values: []string{"merge"},
|
||||
}
|
||||
patchMergeKeyExtension := extension{
|
||||
idlTag: "patchMergeKey",
|
||||
xName: "x-kubernetes-patch-merge-key",
|
||||
values: []string{"key1", "key2"},
|
||||
}
|
||||
listTypeExtension := extension{
|
||||
idlTag: "listType",
|
||||
xName: "x-kubernetes-list-type",
|
||||
values: []string{"atomic"},
|
||||
}
|
||||
listMapKeysExtension := extension{
|
||||
idlTag: "listMapKey",
|
||||
xName: "x-kubernetes-map-keys",
|
||||
values: []string{"key1"},
|
||||
}
|
||||
genExtension := extension{
|
||||
idlTag: "k8s:openapi-gen",
|
||||
xName: "x-kubernetes-member-type",
|
||||
values: []string{"value1"},
|
||||
}
|
||||
|
||||
sliceField := types.Member{
|
||||
Name: "Containers",
|
||||
Type: &types.Type{
|
||||
Kind: types.Slice,
|
||||
},
|
||||
}
|
||||
mapField := types.Member{
|
||||
Name: "Containers",
|
||||
Type: &types.Type{
|
||||
Kind: types.Map,
|
||||
},
|
||||
}
|
||||
|
||||
var successTests = []struct {
|
||||
extensions []extension
|
||||
member types.Member
|
||||
}{
|
||||
// Test single member extension
|
||||
{
|
||||
extensions: []extension{patchStrategyExtension},
|
||||
member: sliceField,
|
||||
},
|
||||
// Test multiple member extensions
|
||||
{
|
||||
extensions: []extension{
|
||||
patchMergeKeyExtension,
|
||||
listTypeExtension,
|
||||
listMapKeysExtension,
|
||||
genExtension, // Should not generate errors during type validation
|
||||
},
|
||||
member: sliceField,
|
||||
},
|
||||
}
|
||||
for _, test := range successTests {
|
||||
errors := validateMemberExtensions(test.extensions, &test.member)
|
||||
if len(errors) > 0 {
|
||||
t.Errorf("validateMemberExtensions: %v should have produced no errors. Errors: %v",
|
||||
test.extensions, errors)
|
||||
}
|
||||
}
|
||||
|
||||
var failureTests = []struct {
|
||||
extensions []extension
|
||||
member types.Member
|
||||
}{
|
||||
// Test single member extension
|
||||
{
|
||||
extensions: []extension{patchStrategyExtension},
|
||||
member: mapField,
|
||||
},
|
||||
// Test multiple member extensions
|
||||
{
|
||||
extensions: []extension{
|
||||
patchMergeKeyExtension,
|
||||
listTypeExtension,
|
||||
listMapKeysExtension,
|
||||
},
|
||||
member: mapField,
|
||||
},
|
||||
}
|
||||
for _, test := range failureTests {
|
||||
errors := validateMemberExtensions(test.extensions, &test.member)
|
||||
if len(errors) != len(test.extensions) {
|
||||
t.Errorf("validateMemberExtensions: %v should have produced all errors. Errors: %v",
|
||||
test.extensions, errors)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
607
vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
607
vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
generated
vendored
@@ -1,607 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// This is the comment tag that carries parameters for open API generation.
|
||||
const tagName = "k8s:openapi-gen"
|
||||
const tagOptional = "optional"
|
||||
|
||||
// Known values for the tag.
|
||||
const (
|
||||
tagValueTrue = "true"
|
||||
tagValueFalse = "false"
|
||||
)
|
||||
|
||||
// Used for temporary validation of patch struct tags.
|
||||
// TODO: Remove patch struct tag validation because they we are now consuming OpenAPI on server.
|
||||
var tempPatchTags = [...]string{
|
||||
"patchMergeKey",
|
||||
"patchStrategy",
|
||||
}
|
||||
|
||||
func getOpenAPITagValue(comments []string) []string {
|
||||
return types.ExtractCommentTags("+", comments)[tagName]
|
||||
}
|
||||
|
||||
func getSingleTagsValue(comments []string, tag string) (string, error) {
|
||||
tags, ok := types.ExtractCommentTags("+", comments)[tag]
|
||||
if !ok || len(tags) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
if len(tags) > 1 {
|
||||
return "", fmt.Errorf("multiple values are not allowed for tag %s", tag)
|
||||
}
|
||||
return tags[0], nil
|
||||
}
|
||||
|
||||
func hasOpenAPITagValue(comments []string, value string) bool {
|
||||
tagValues := getOpenAPITagValue(comments)
|
||||
for _, val := range tagValues {
|
||||
if val == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasOptionalTag returns true if the member has +optional in its comments or
|
||||
// omitempty in its json tags.
|
||||
func hasOptionalTag(m *types.Member) bool {
|
||||
hasOptionalCommentTag := types.ExtractCommentTags(
|
||||
"+", m.CommentLines)[tagOptional] != nil
|
||||
hasOptionalJsonTag := strings.Contains(
|
||||
reflect.StructTag(m.Tags).Get("json"), "omitempty")
|
||||
return hasOptionalCommentTag || hasOptionalJsonTag
|
||||
}
|
||||
|
||||
func apiTypeFilterFunc(c *generator.Context, t *types.Type) bool {
|
||||
// There is a conflict between this codegen and codecgen, we should avoid types generated for codecgen
|
||||
if strings.HasPrefix(t.Name.Name, "codecSelfer") {
|
||||
return false
|
||||
}
|
||||
pkg := c.Universe.Package(t.Name.Package)
|
||||
if hasOpenAPITagValue(pkg.Comments, tagValueTrue) {
|
||||
return !hasOpenAPITagValue(t.CommentLines, tagValueFalse)
|
||||
}
|
||||
if hasOpenAPITagValue(t.CommentLines, tagValueTrue) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const (
|
||||
specPackagePath = "github.com/go-openapi/spec"
|
||||
openAPICommonPackagePath = "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// openApiGen produces a file with auto-generated OpenAPI functions.
|
||||
type openAPIGen struct {
|
||||
generator.DefaultGen
|
||||
// TargetPackage is the package that will get GetOpenAPIDefinitions function returns all open API definitions.
|
||||
targetPackage string
|
||||
imports namer.ImportTracker
|
||||
}
|
||||
|
||||
func newOpenAPIGen(sanitizedName string, targetPackage string) generator.Generator {
|
||||
return &openAPIGen{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
imports: generator.NewImportTracker(),
|
||||
targetPackage: targetPackage,
|
||||
}
|
||||
}
|
||||
|
||||
const nameTmpl = "schema_$.type|private$"
|
||||
|
||||
func (g *openAPIGen) Namers(c *generator.Context) namer.NameSystems {
|
||||
// Have the raw namer for this file track what it imports.
|
||||
return namer.NameSystems{
|
||||
"raw": namer.NewRawNamer(g.targetPackage, g.imports),
|
||||
"private": &namer.NameStrategy{
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return strings.Join(in, "_")
|
||||
},
|
||||
PrependPackageNames: 4, // enough to fully qualify from k8s.io/api/...
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (g *openAPIGen) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.targetPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *openAPIGen) Imports(c *generator.Context) []string {
|
||||
importLines := []string{}
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func argsFromType(t *types.Type) generator.Args {
|
||||
return generator.Args{
|
||||
"type": t,
|
||||
"ReferenceCallback": types.Ref(openAPICommonPackagePath, "ReferenceCallback"),
|
||||
"OpenAPIDefinition": types.Ref(openAPICommonPackagePath, "OpenAPIDefinition"),
|
||||
"SpecSchemaType": types.Ref(specPackagePath, "Schema"),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *openAPIGen) Init(c *generator.Context, w io.Writer) error {
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
sw.Do("func GetOpenAPIDefinitions(ref $.ReferenceCallback|raw$) map[string]$.OpenAPIDefinition|raw$ {\n", argsFromType(nil))
|
||||
sw.Do("return map[string]$.OpenAPIDefinition|raw${\n", argsFromType(nil))
|
||||
|
||||
for _, t := range c.Order {
|
||||
err := newOpenAPITypeWriter(sw).generateCall(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
sw.Do("}\n", nil)
|
||||
sw.Do("}\n\n", nil)
|
||||
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func (g *openAPIGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
klog.V(5).Infof("generating for type %v", t)
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
err := newOpenAPITypeWriter(sw).generate(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sw.Error()
|
||||
}
|
||||
|
||||
func getJsonTags(m *types.Member) []string {
|
||||
jsonTag := reflect.StructTag(m.Tags).Get("json")
|
||||
if jsonTag == "" {
|
||||
return []string{}
|
||||
}
|
||||
return strings.Split(jsonTag, ",")
|
||||
}
|
||||
|
||||
func getReferableName(m *types.Member) string {
|
||||
jsonTags := getJsonTags(m)
|
||||
if len(jsonTags) > 0 {
|
||||
if jsonTags[0] == "-" {
|
||||
return ""
|
||||
} else {
|
||||
return jsonTags[0]
|
||||
}
|
||||
} else {
|
||||
return m.Name
|
||||
}
|
||||
}
|
||||
|
||||
func shouldInlineMembers(m *types.Member) bool {
|
||||
jsonTags := getJsonTags(m)
|
||||
return len(jsonTags) > 1 && jsonTags[1] == "inline"
|
||||
}
|
||||
|
||||
type openAPITypeWriter struct {
|
||||
*generator.SnippetWriter
|
||||
refTypes map[string]*types.Type
|
||||
GetDefinitionInterface *types.Type
|
||||
}
|
||||
|
||||
func newOpenAPITypeWriter(sw *generator.SnippetWriter) openAPITypeWriter {
|
||||
return openAPITypeWriter{
|
||||
SnippetWriter: sw,
|
||||
refTypes: map[string]*types.Type{},
|
||||
}
|
||||
}
|
||||
|
||||
func methodReturnsValue(mt *types.Type, pkg, name string) bool {
|
||||
if len(mt.Signature.Parameters) != 0 || len(mt.Signature.Results) != 1 {
|
||||
return false
|
||||
}
|
||||
r := mt.Signature.Results[0]
|
||||
return r.Name.Name == name && r.Name.Package == pkg
|
||||
}
|
||||
|
||||
func hasOpenAPIDefinitionMethod(t *types.Type) bool {
|
||||
for mn, mt := range t.Methods {
|
||||
if mn != "OpenAPIDefinition" {
|
||||
continue
|
||||
}
|
||||
return methodReturnsValue(mt, openAPICommonPackagePath, "OpenAPIDefinition")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasOpenAPIDefinitionMethods(t *types.Type) bool {
|
||||
var hasSchemaTypeMethod, hasOpenAPISchemaFormat bool
|
||||
for mn, mt := range t.Methods {
|
||||
switch mn {
|
||||
case "OpenAPISchemaType":
|
||||
hasSchemaTypeMethod = methodReturnsValue(mt, "", "[]string")
|
||||
case "OpenAPISchemaFormat":
|
||||
hasOpenAPISchemaFormat = methodReturnsValue(mt, "", "string")
|
||||
}
|
||||
}
|
||||
return hasSchemaTypeMethod && hasOpenAPISchemaFormat
|
||||
}
|
||||
|
||||
// typeShortName returns short package name (e.g. the name x appears in package x definition) dot type name.
|
||||
func typeShortName(t *types.Type) string {
|
||||
return filepath.Base(t.Name.Package) + "." + t.Name.Name
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMembers(t *types.Type, required []string) ([]string, error) {
|
||||
var err error
|
||||
for _, m := range t.Members {
|
||||
if hasOpenAPITagValue(m.CommentLines, tagValueFalse) {
|
||||
continue
|
||||
}
|
||||
if shouldInlineMembers(&m) {
|
||||
required, err = g.generateMembers(m.Type, required)
|
||||
if err != nil {
|
||||
return required, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
name := getReferableName(&m)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if !hasOptionalTag(&m) {
|
||||
required = append(required, name)
|
||||
}
|
||||
if err = g.generateProperty(&m, t); err != nil {
|
||||
klog.Errorf("Error when generating: %v, %v\n", name, m)
|
||||
return required, err
|
||||
}
|
||||
}
|
||||
return required, nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateCall(t *types.Type) error {
|
||||
// Only generate for struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
args := argsFromType(t)
|
||||
g.Do("\"$.$\": ", t.Name)
|
||||
if hasOpenAPIDefinitionMethod(t) {
|
||||
g.Do("$.type|raw${}.OpenAPIDefinition(),\n", args)
|
||||
} else {
|
||||
g.Do(nameTmpl+"(ref),\n", args)
|
||||
}
|
||||
}
|
||||
return g.Error()
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generate(t *types.Type) error {
|
||||
// Only generate for struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
if hasOpenAPIDefinitionMethod(t) {
|
||||
// already invoked directly
|
||||
return nil
|
||||
}
|
||||
|
||||
args := argsFromType(t)
|
||||
g.Do("func "+nameTmpl+"(ref $.ReferenceCallback|raw$) $.OpenAPIDefinition|raw$ {\n", args)
|
||||
if hasOpenAPIDefinitionMethods(t) {
|
||||
g.Do("return $.OpenAPIDefinition|raw${\n"+
|
||||
"Schema: spec.Schema{\n"+
|
||||
"SchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Type:$.type|raw${}.OpenAPISchemaType(),\n"+
|
||||
"Format:$.type|raw${}.OpenAPISchemaFormat(),\n"+
|
||||
"},\n"+
|
||||
"},\n"+
|
||||
"}\n}\n\n", args)
|
||||
return nil
|
||||
}
|
||||
g.Do("return $.OpenAPIDefinition|raw${\nSchema: spec.Schema{\nSchemaProps: spec.SchemaProps{\n", args)
|
||||
g.generateDescription(t.CommentLines)
|
||||
g.Do("Properties: map[string]$.SpecSchemaType|raw${\n", args)
|
||||
required, err := g.generateMembers(t, []string{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
if len(required) > 0 {
|
||||
g.Do("Required: []string{\"$.$\"},\n", strings.Join(required, "\",\""))
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
if err := g.generateStructExtensions(t); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("},\n", nil)
|
||||
g.Do("Dependencies: []string{\n", args)
|
||||
// Map order is undefined, sort them or we may get a different file generated each time.
|
||||
keys := []string{}
|
||||
for k := range g.refTypes {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := g.refTypes[k]
|
||||
if t, _ := openapi.GetOpenAPITypeFormat(v.String()); t != "" {
|
||||
// This is a known type, we do not need a reference to it
|
||||
// Will eliminate special case of time.Time
|
||||
continue
|
||||
}
|
||||
g.Do("\"$.$\",", k)
|
||||
}
|
||||
g.Do("},\n}\n}\n\n", nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateStructExtensions(t *types.Type) error {
|
||||
extensions, errors := parseExtensions(t.CommentLines)
|
||||
// Initially, we will only log struct extension errors.
|
||||
if len(errors) > 0 {
|
||||
for _, e := range errors {
|
||||
klog.V(2).Infof("[%s]: %s\n", t.String(), e)
|
||||
}
|
||||
}
|
||||
// TODO(seans3): Validate struct extensions here.
|
||||
g.emitExtensions(extensions)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMemberExtensions(m *types.Member, parent *types.Type) error {
|
||||
extensions, parseErrors := parseExtensions(m.CommentLines)
|
||||
validationErrors := validateMemberExtensions(extensions, m)
|
||||
errors := append(parseErrors, validationErrors...)
|
||||
// Initially, we will only log member extension errors.
|
||||
if len(errors) > 0 {
|
||||
errorPrefix := fmt.Sprintf("[%s] %s:", parent.String(), m.String())
|
||||
for _, e := range errors {
|
||||
klog.V(2).Infof("%s %s\n", errorPrefix, e)
|
||||
}
|
||||
}
|
||||
g.emitExtensions(extensions)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) emitExtensions(extensions []extension) {
|
||||
// If any extensions exist, then emit code to create them.
|
||||
if len(extensions) == 0 {
|
||||
return
|
||||
}
|
||||
g.Do("VendorExtensible: spec.VendorExtensible{\nExtensions: spec.Extensions{\n", nil)
|
||||
for _, extension := range extensions {
|
||||
g.Do("\"$.$\": ", extension.xName)
|
||||
if extension.hasMultipleValues() {
|
||||
g.Do("[]string{\n", nil)
|
||||
}
|
||||
for _, value := range extension.values {
|
||||
g.Do("\"$.$\",\n", value)
|
||||
}
|
||||
if extension.hasMultipleValues() {
|
||||
g.Do("},\n", nil)
|
||||
}
|
||||
}
|
||||
g.Do("},\n},\n", nil)
|
||||
}
|
||||
|
||||
// TODO(#44005): Move this validation outside of this generator (probably to policy verifier)
|
||||
func (g openAPITypeWriter) validatePatchTags(m *types.Member, parent *types.Type) error {
|
||||
// TODO: Remove patch struct tag validation because they we are now consuming OpenAPI on server.
|
||||
for _, tagKey := range tempPatchTags {
|
||||
structTagValue := reflect.StructTag(m.Tags).Get(tagKey)
|
||||
commentTagValue, err := getSingleTagsValue(m.CommentLines, tagKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if structTagValue != commentTagValue {
|
||||
return fmt.Errorf("Tags in comment and struct should match for member (%s) of (%s)",
|
||||
m.Name, parent.Name.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateDescription(CommentLines []string) {
|
||||
var buffer bytes.Buffer
|
||||
delPrevChar := func() {
|
||||
if buffer.Len() > 0 {
|
||||
buffer.Truncate(buffer.Len() - 1) // Delete the last " " or "\n"
|
||||
}
|
||||
}
|
||||
|
||||
for _, line := range CommentLines {
|
||||
// Ignore all lines after ---
|
||||
if line == "---" {
|
||||
break
|
||||
}
|
||||
line = strings.TrimRight(line, " ")
|
||||
leading := strings.TrimLeft(line, " ")
|
||||
switch {
|
||||
case len(line) == 0: // Keep paragraphs
|
||||
delPrevChar()
|
||||
buffer.WriteString("\n\n")
|
||||
case strings.HasPrefix(leading, "TODO"): // Ignore one line TODOs
|
||||
case strings.HasPrefix(leading, "+"): // Ignore instructions to go2idl
|
||||
default:
|
||||
if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") {
|
||||
delPrevChar()
|
||||
line = "\n" + line + "\n" // Replace it with newline. This is useful when we have a line with: "Example:\n\tJSON-someting..."
|
||||
} else {
|
||||
line += " "
|
||||
}
|
||||
buffer.WriteString(line)
|
||||
}
|
||||
}
|
||||
|
||||
postDoc := strings.TrimRight(buffer.String(), "\n")
|
||||
postDoc = strings.Replace(postDoc, "\\\"", "\"", -1) // replace user's \" to "
|
||||
postDoc = strings.Replace(postDoc, "\"", "\\\"", -1) // Escape "
|
||||
postDoc = strings.Replace(postDoc, "\n", "\\n", -1)
|
||||
postDoc = strings.Replace(postDoc, "\t", "\\t", -1)
|
||||
postDoc = strings.Trim(postDoc, " ")
|
||||
if postDoc != "" {
|
||||
g.Do("Description: \"$.$\",\n", postDoc)
|
||||
}
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateProperty(m *types.Member, parent *types.Type) error {
|
||||
name := getReferableName(m)
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
if err := g.validatePatchTags(m, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("\"$.$\": {\n", name)
|
||||
if err := g.generateMemberExtensions(m, parent); err != nil {
|
||||
return err
|
||||
}
|
||||
g.Do("SchemaProps: spec.SchemaProps{\n", nil)
|
||||
g.generateDescription(m.CommentLines)
|
||||
jsonTags := getJsonTags(m)
|
||||
if len(jsonTags) > 1 && jsonTags[1] == "string" {
|
||||
g.generateSimpleProperty("string", "")
|
||||
g.Do("},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
t := resolveAliasAndPtrType(m.Type)
|
||||
// If we can get a openAPI type and format for this type, we consider it to be simple property
|
||||
typeString, format := openapi.GetOpenAPITypeFormat(t.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
g.Do("},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch t.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", t)
|
||||
case types.Map:
|
||||
if err := g.generateMapProperty(t); err != nil {
|
||||
return err
|
||||
}
|
||||
case types.Slice, types.Array:
|
||||
if err := g.generateSliceProperty(t); err != nil {
|
||||
return err
|
||||
}
|
||||
case types.Struct, types.Interface:
|
||||
g.generateReferenceProperty(t)
|
||||
default:
|
||||
return fmt.Errorf("cannot generate spec for type %v", t)
|
||||
}
|
||||
g.Do("},\n},\n", nil)
|
||||
return g.Error()
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateSimpleProperty(typeString, format string) {
|
||||
g.Do("Type: []string{\"$.$\"},\n", typeString)
|
||||
g.Do("Format: \"$.$\",\n", format)
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateReferenceProperty(t *types.Type) {
|
||||
g.refTypes[t.Name.String()] = t
|
||||
g.Do("Ref: ref(\"$.$\"),\n", t.Name.String())
|
||||
}
|
||||
|
||||
func resolveAliasAndPtrType(t *types.Type) *types.Type {
|
||||
var prev *types.Type
|
||||
for prev != t {
|
||||
prev = t
|
||||
if t.Kind == types.Alias {
|
||||
t = t.Underlying
|
||||
}
|
||||
if t.Kind == types.Pointer {
|
||||
t = t.Elem
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateMapProperty(t *types.Type) error {
|
||||
keyType := resolveAliasAndPtrType(t.Key)
|
||||
elemType := resolveAliasAndPtrType(t.Elem)
|
||||
|
||||
// According to OpenAPI examples, only map from string is supported
|
||||
if keyType.Name.Name != "string" {
|
||||
return fmt.Errorf("map with non-string keys are not supported by OpenAPI in %v", t)
|
||||
}
|
||||
g.Do("Type: []string{\"object\"},\n", nil)
|
||||
g.Do("AdditionalProperties: &spec.SchemaOrBool{\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil)
|
||||
typeString, format := openapi.GetOpenAPITypeFormat(elemType.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch elemType.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType)
|
||||
case types.Struct:
|
||||
g.generateReferenceProperty(elemType)
|
||||
case types.Slice, types.Array:
|
||||
g.generateSliceProperty(elemType)
|
||||
default:
|
||||
return fmt.Errorf("map Element kind %v is not supported in %v", elemType.Kind, t.Name)
|
||||
}
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g openAPITypeWriter) generateSliceProperty(t *types.Type) error {
|
||||
elemType := resolveAliasAndPtrType(t.Elem)
|
||||
g.Do("Type: []string{\"array\"},\n", nil)
|
||||
g.Do("Items: &spec.SchemaOrArray{\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil)
|
||||
typeString, format := openapi.GetOpenAPITypeFormat(elemType.String())
|
||||
if typeString != "" {
|
||||
g.generateSimpleProperty(typeString, format)
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
||||
switch elemType.Kind {
|
||||
case types.Builtin:
|
||||
return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType)
|
||||
case types.Struct:
|
||||
g.generateReferenceProperty(elemType)
|
||||
case types.Slice, types.Array:
|
||||
g.generateSliceProperty(elemType)
|
||||
default:
|
||||
return fmt.Errorf("slice Element kind %v is not supported in %v", elemType.Kind, t)
|
||||
}
|
||||
g.Do("},\n},\n},\n", nil)
|
||||
return nil
|
||||
}
|
625
vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go
generated
vendored
625
vendor/k8s.io/kube-openapi/pkg/generators/openapi_test.go
generated
vendored
@@ -1,625 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 generators
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/parser"
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
func construct(t *testing.T, files map[string]string, testNamer namer.Namer) (*parser.Builder, types.Universe, []*types.Type) {
|
||||
b := parser.New()
|
||||
for name, src := range files {
|
||||
if err := b.AddFileForTest(filepath.Dir(name), name, []byte(src)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
u, err := b.FindTypes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
orderer := namer.Orderer{Namer: testNamer}
|
||||
o := orderer.OrderUniverse(u)
|
||||
return b, u, o
|
||||
}
|
||||
|
||||
func testOpenAPITypeWriter(t *testing.T, code string) (error, error, *assert.Assertions, *bytes.Buffer, *bytes.Buffer) {
|
||||
assert := assert.New(t)
|
||||
var testFiles = map[string]string{
|
||||
"base/foo/bar.go": code,
|
||||
}
|
||||
rawNamer := namer.NewRawNamer("o", nil)
|
||||
namers := namer.NameSystems{
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
"private": &namer.NameStrategy{
|
||||
Join: func(pre string, in []string, post string) string {
|
||||
return strings.Join(in, "_")
|
||||
},
|
||||
PrependPackageNames: 4, // enough to fully qualify from k8s.io/api/...
|
||||
},
|
||||
}
|
||||
builder, universe, _ := construct(t, testFiles, rawNamer)
|
||||
context, err := generator.NewContext(builder, namers, "raw")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
blahT := universe.Type(types.Name{Package: "base/foo", Name: "Blah"})
|
||||
|
||||
callBuffer := &bytes.Buffer{}
|
||||
callSW := generator.NewSnippetWriter(callBuffer, context, "$", "$")
|
||||
callError := newOpenAPITypeWriter(callSW).generateCall(blahT)
|
||||
|
||||
funcBuffer := &bytes.Buffer{}
|
||||
funcSW := generator.NewSnippetWriter(funcBuffer, context, "$", "$")
|
||||
funcError := newOpenAPITypeWriter(funcSW).generate(blahT)
|
||||
|
||||
return callError, funcError, assert, callBuffer, funcBuffer
|
||||
}
|
||||
|
||||
func TestSimple(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Blah is a test.
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:openapi-gen=x-kubernetes-type-tag:type_test
|
||||
type Blah struct {
|
||||
// A simple string
|
||||
String string
|
||||
// A simple int
|
||||
Int int `+"`"+`json:",omitempty"`+"`"+`
|
||||
// An int considered string simple int
|
||||
IntString int `+"`"+`json:",string"`+"`"+`
|
||||
// A simple int64
|
||||
Int64 int64
|
||||
// A simple int32
|
||||
Int32 int32
|
||||
// A simple int16
|
||||
Int16 int16
|
||||
// A simple int8
|
||||
Int8 int8
|
||||
// A simple int
|
||||
Uint uint
|
||||
// A simple int64
|
||||
Uint64 uint64
|
||||
// A simple int32
|
||||
Uint32 uint32
|
||||
// A simple int16
|
||||
Uint16 uint16
|
||||
// A simple int8
|
||||
Uint8 uint8
|
||||
// A simple byte
|
||||
Byte byte
|
||||
// A simple boolean
|
||||
Bool bool
|
||||
// A simple float64
|
||||
Float64 float64
|
||||
// A simple float32
|
||||
Float32 float32
|
||||
// a base64 encoded characters
|
||||
ByteArray []byte
|
||||
// a member with an extension
|
||||
// +k8s:openapi-gen=x-kubernetes-member-tag:member_test
|
||||
WithExtension string
|
||||
// a member with struct tag as extension
|
||||
// +patchStrategy=merge
|
||||
// +patchMergeKey=pmk
|
||||
WithStructTagExtension string `+"`"+`patchStrategy:"merge" patchMergeKey:"pmk"`+"`"+`
|
||||
// a member with a list type
|
||||
// +listType=atomic
|
||||
WithListType []string
|
||||
}
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": schema_base_foo_Blah(ref),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Blah is a test.",
|
||||
Properties: map[string]spec.Schema{
|
||||
"String": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple string",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"Int64": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int64",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"Int32": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int32",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"Int16": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int16",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"Int8": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int8",
|
||||
Type: []string{"integer"},
|
||||
Format: "byte",
|
||||
},
|
||||
},
|
||||
"Uint": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"Uint64": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int64",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"Uint32": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int32",
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
"Uint16": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int16",
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"Uint8": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple int8",
|
||||
Type: []string{"integer"},
|
||||
Format: "byte",
|
||||
},
|
||||
},
|
||||
"Byte": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple byte",
|
||||
Type: []string{"integer"},
|
||||
Format: "byte",
|
||||
},
|
||||
},
|
||||
"Bool": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple boolean",
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"Float64": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple float64",
|
||||
Type: []string{"number"},
|
||||
Format: "double",
|
||||
},
|
||||
},
|
||||
"Float32": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A simple float32",
|
||||
Type: []string{"number"},
|
||||
Format: "float",
|
||||
},
|
||||
},
|
||||
"ByteArray": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "a base64 encoded characters",
|
||||
Type: []string{"string"},
|
||||
Format: "byte",
|
||||
},
|
||||
},
|
||||
"WithExtension": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-member-tag": "member_test",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "a member with an extension",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"WithStructTagExtension": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-patch-merge-key": "pmk",
|
||||
"x-kubernetes-patch-strategy": "merge",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "a member with struct tag as extension",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"WithListType": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "a member with a list type",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"String","Int64","Int32","Int16","Int8","Uint","Uint64","Uint32","Uint16","Uint8","Byte","Bool","Float64","Float32","ByteArray","WithExtension","WithStructTagExtension","WithListType"},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-type-tag": "type_test",
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
`, funcBuffer.String())
|
||||
}
|
||||
|
||||
func TestFailingSample1(t *testing.T) {
|
||||
_, funcErr, assert, _, _ := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Map sample tests openAPIGen.generateMapProperty method.
|
||||
type Blah struct {
|
||||
// A sample String to String map
|
||||
StringToArray map[string]map[string]string
|
||||
}
|
||||
`)
|
||||
if assert.Error(funcErr, "An error was expected") {
|
||||
assert.Equal(funcErr, fmt.Errorf("map Element kind Map is not supported in map[string]map[string]string"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailingSample2(t *testing.T) {
|
||||
_, funcErr, assert, _, _ := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Map sample tests openAPIGen.generateMapProperty method.
|
||||
type Blah struct {
|
||||
// A sample String to String map
|
||||
StringToArray map[int]string
|
||||
} `)
|
||||
if assert.Error(funcErr, "An error was expected") {
|
||||
assert.Equal(funcErr, fmt.Errorf("map with non-string keys are not supported by OpenAPI in map[int]string"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomDef(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
import openapi "k8s.io/kube-openapi/pkg/common"
|
||||
|
||||
type Blah struct {
|
||||
}
|
||||
|
||||
func (_ Blah) OpenAPIDefinition() openapi.OpenAPIDefinition {
|
||||
return openapi.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "date-time",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": foo.Blah{}.OpenAPIDefinition(),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(``, funcBuffer.String())
|
||||
}
|
||||
|
||||
func TestCustomDefs(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Blah is a custom type
|
||||
type Blah struct {
|
||||
}
|
||||
|
||||
func (_ Blah) OpenAPISchemaType() []string { return []string{"string"} }
|
||||
func (_ Blah) OpenAPISchemaFormat() string { return "date-time" }
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": schema_base_foo_Blah(ref),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Blah is a custom type",
|
||||
Type:foo.Blah{}.OpenAPISchemaType(),
|
||||
Format:foo.Blah{}.OpenAPISchemaFormat(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
`, funcBuffer.String())
|
||||
}
|
||||
|
||||
func TestPointer(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// PointerSample demonstrate pointer's properties
|
||||
type Blah struct {
|
||||
// A string pointer
|
||||
StringPointer *string
|
||||
// A struct pointer
|
||||
StructPointer *Blah
|
||||
// A slice pointer
|
||||
SlicePointer *[]string
|
||||
// A map pointer
|
||||
MapPointer *map[string]string
|
||||
}
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": schema_base_foo_Blah(ref),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "PointerSample demonstrate pointer's properties",
|
||||
Properties: map[string]spec.Schema{
|
||||
"StringPointer": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A string pointer",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"StructPointer": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A struct pointer",
|
||||
Ref: ref("base/foo.Blah"),
|
||||
},
|
||||
},
|
||||
"SlicePointer": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A slice pointer",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"MapPointer": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "A map pointer",
|
||||
Type: []string{"object"},
|
||||
AdditionalProperties: &spec.SchemaOrBool{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"StringPointer","StructPointer","SlicePointer","MapPointer"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"base/foo.Blah",},
|
||||
}
|
||||
}
|
||||
|
||||
`, funcBuffer.String())
|
||||
}
|
||||
|
||||
func TestNestedLists(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Blah is a test.
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:openapi-gen=x-kubernetes-type-tag:type_test
|
||||
type Blah struct {
|
||||
// Nested list
|
||||
NestedList [][]int64
|
||||
}
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": schema_base_foo_Blah(ref),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Blah is a test.",
|
||||
Properties: map[string]spec.Schema{
|
||||
"NestedList": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Nested list",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int64",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"NestedList"},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-type-tag": "type_test",
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
`, funcBuffer.String())
|
||||
}
|
||||
|
||||
func TestExtensions(t *testing.T) {
|
||||
callErr, funcErr, assert, callBuffer, funcBuffer := testOpenAPITypeWriter(t, `
|
||||
package foo
|
||||
|
||||
// Blah is a test.
|
||||
// +k8s:openapi-gen=true
|
||||
// +k8s:openapi-gen=x-kubernetes-type-tag:type_test
|
||||
type Blah struct {
|
||||
// a member with a list type
|
||||
// +listType=map
|
||||
// +listMapKey=port
|
||||
// +listMapKey=protocol
|
||||
WithListField []string
|
||||
}
|
||||
`)
|
||||
if callErr != nil {
|
||||
t.Fatal(callErr)
|
||||
}
|
||||
if funcErr != nil {
|
||||
t.Fatal(funcErr)
|
||||
}
|
||||
assert.Equal(`"base/foo.Blah": schema_base_foo_Blah(ref),
|
||||
`, callBuffer.String())
|
||||
assert.Equal(`func schema_base_foo_Blah(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "Blah is a test.",
|
||||
Properties: map[string]spec.Schema{
|
||||
"WithListField": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": []string{
|
||||
"port",
|
||||
"protocol",
|
||||
},
|
||||
"x-kubernetes-list-type": "map",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "a member with a list type",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"WithListField"},
|
||||
},
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-type-tag": "type_test",
|
||||
},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
`, funcBuffer.String())
|
||||
}
|
4
vendor/k8s.io/kube-openapi/pkg/generators/rules/OWNERS
generated
vendored
4
vendor/k8s.io/kube-openapi/pkg/generators/rules/OWNERS
generated
vendored
@@ -1,4 +0,0 @@
|
||||
reviewers:
|
||||
- roycaihw
|
||||
approvers:
|
||||
- roycaihw
|
23
vendor/k8s.io/kube-openapi/pkg/generators/rules/doc.go
generated
vendored
23
vendor/k8s.io/kube-openapi/pkg/generators/rules/doc.go
generated
vendored
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 rules contains API rules that are enforced in OpenAPI spec generation
|
||||
// as part of the machinery. Files under this package implement APIRule interface
|
||||
// which evaluates Go type and produces list of API rule violations.
|
||||
//
|
||||
// Implementations of APIRule should be added to API linter under openAPIGen code-
|
||||
// generator to get integrated in the generation process.
|
||||
package rules
|
172
vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match.go
generated
vendored
172
vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match.go
generated
vendored
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/sets"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
var (
|
||||
// Blacklist of JSON tags that should skip match evaluation
|
||||
jsonTagBlacklist = sets.NewString(
|
||||
// Omitted field is ignored by the package
|
||||
"-",
|
||||
)
|
||||
|
||||
// Blacklist of JSON names that should skip match evaluation
|
||||
jsonNameBlacklist = sets.NewString(
|
||||
// Empty name is used for inline struct field (e.g. metav1.TypeMeta)
|
||||
"",
|
||||
// Special case for object and list meta
|
||||
"metadata",
|
||||
)
|
||||
|
||||
// List of substrings that aren't allowed in Go name and JSON name
|
||||
disallowedNameSubstrings = sets.NewString(
|
||||
// Underscore is not allowed in either name
|
||||
"_",
|
||||
// Dash is not allowed in either name. Note that since dash is a valid JSON tag, this should be checked
|
||||
// after JSON tag blacklist check.
|
||||
"-",
|
||||
)
|
||||
)
|
||||
|
||||
/*
|
||||
NamesMatch implements APIRule interface.
|
||||
Go field names must be CamelCase. JSON field names must be camelCase. Other than capitalization of the
|
||||
initial letter, the two should almost always match. No underscores nor dashes in either.
|
||||
This rule verifies the convention "Other than capitalization of the initial letter, the two should almost always match."
|
||||
Examples (also in unit test):
|
||||
Go name | JSON name | match
|
||||
podSpec false
|
||||
PodSpec podSpec true
|
||||
PodSpec PodSpec false
|
||||
podSpec podSpec false
|
||||
PodSpec spec false
|
||||
Spec podSpec false
|
||||
JSONSpec jsonSpec true
|
||||
JSONSpec jsonspec false
|
||||
HTTPJSONSpec httpJSONSpec true
|
||||
NOTE: this validator cannot tell two sequential all-capital words from one word, therefore the case below
|
||||
is also considered matched.
|
||||
HTTPJSONSpec httpjsonSpec true
|
||||
NOTE: JSON names in jsonNameBlacklist should skip evaluation
|
||||
true
|
||||
podSpec true
|
||||
podSpec - true
|
||||
podSpec metadata true
|
||||
*/
|
||||
type NamesMatch struct{}
|
||||
|
||||
// Name returns the name of APIRule
|
||||
func (n *NamesMatch) Name() string {
|
||||
return "names_match"
|
||||
}
|
||||
|
||||
// Validate evaluates API rule on type t and returns a list of field names in
|
||||
// the type that violate the rule. Empty field name [""] implies the entire
|
||||
// type violates the rule.
|
||||
func (n *NamesMatch) Validate(t *types.Type) ([]string, error) {
|
||||
fields := make([]string, 0)
|
||||
|
||||
// Only validate struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range t.Members {
|
||||
goName := m.Name
|
||||
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
|
||||
// Distinguish empty JSON tag and missing JSON tag. Empty JSON tag / name is
|
||||
// allowed (in JSON name blacklist) but missing JSON tag is invalid.
|
||||
if !ok {
|
||||
fields = append(fields, goName)
|
||||
continue
|
||||
}
|
||||
if jsonTagBlacklist.Has(jsonTag) {
|
||||
continue
|
||||
}
|
||||
jsonName := strings.Split(jsonTag, ",")[0]
|
||||
if !namesMatch(goName, jsonName) {
|
||||
fields = append(fields, goName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
// namesMatch evaluates if goName and jsonName match the API rule
|
||||
// TODO: Use an off-the-shelf CamelCase solution instead of implementing this logic. The following existing
|
||||
// packages have been tried out:
|
||||
// github.com/markbates/inflect
|
||||
// github.com/segmentio/go-camelcase
|
||||
// github.com/iancoleman/strcase
|
||||
// github.com/fatih/camelcase
|
||||
// Please see https://github.com/kubernetes/kube-openapi/pull/83#issuecomment-400842314 for more details
|
||||
// about why they don't satisfy our need. What we need can be a function that detects an acronym at the
|
||||
// beginning of a string.
|
||||
func namesMatch(goName, jsonName string) bool {
|
||||
if jsonNameBlacklist.Has(jsonName) {
|
||||
return true
|
||||
}
|
||||
if !isAllowedName(goName) || !isAllowedName(jsonName) {
|
||||
return false
|
||||
}
|
||||
if strings.ToLower(goName) != strings.ToLower(jsonName) {
|
||||
return false
|
||||
}
|
||||
// Go field names must be CamelCase. JSON field names must be camelCase.
|
||||
if !isCapital(goName[0]) || isCapital(jsonName[0]) {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < len(goName); i++ {
|
||||
if goName[i] == jsonName[i] {
|
||||
// goName[0:i-1] is uppercase and jsonName[0:i-1] is lowercase, goName[i:]
|
||||
// and jsonName[i:] should match;
|
||||
// goName[i] should be lowercase if i is equal to 1, e.g.:
|
||||
// goName | jsonName
|
||||
// PodSpec podSpec
|
||||
// or uppercase if i is greater than 1, e.g.:
|
||||
// goname | jsonName
|
||||
// JSONSpec jsonSpec
|
||||
// This is to rule out cases like:
|
||||
// goname | jsonName
|
||||
// JSONSpec jsonspec
|
||||
return goName[i:] == jsonName[i:] && (i == 1 || isCapital(goName[i]))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// isCaptical returns true if one character is capital
|
||||
func isCapital(b byte) bool {
|
||||
return b >= 'A' && b <= 'Z'
|
||||
}
|
||||
|
||||
// isAllowedName checks the list of disallowedNameSubstrings and returns true if name doesn't contain
|
||||
// any disallowed substring.
|
||||
func isAllowedName(name string) bool {
|
||||
for _, substr := range disallowedNameSubstrings.UnsortedList() {
|
||||
if strings.Contains(name, substr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
359
vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match_test.go
generated
vendored
359
vendor/k8s.io/kube-openapi/pkg/generators/rules/names_match_test.go
generated
vendored
@@ -1,359 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
func TestNamesMatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
// name of test case
|
||||
name string
|
||||
t *types.Type
|
||||
|
||||
// expected list of violation fields
|
||||
expected []string
|
||||
}{
|
||||
// The comments are in format of {goName, jsonName, match},
|
||||
// {"PodSpec", "podSpec", true},
|
||||
{
|
||||
name: "simple",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"PodSpec", "podSpec", true},
|
||||
{
|
||||
name: "multiple_json_tags",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec,omitempty"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"PodSpec", "podSpec", true},
|
||||
{
|
||||
name: "protobuf_tag",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec,omitempty" protobuf:"bytes,1,opt,name=podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"", "podSpec", false},
|
||||
{
|
||||
name: "empty",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "",
|
||||
Tags: `json:"podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{""},
|
||||
},
|
||||
// {"PodSpec", "PodSpec", false},
|
||||
{
|
||||
name: "CamelCase_CamelCase",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"PodSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"PodSpec"},
|
||||
},
|
||||
// {"podSpec", "podSpec", false},
|
||||
{
|
||||
name: "camelCase_camelCase",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "podSpec",
|
||||
Tags: `json:"podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"podSpec"},
|
||||
},
|
||||
// {"PodSpec", "spec", false},
|
||||
{
|
||||
name: "short_json_name",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"spec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"PodSpec"},
|
||||
},
|
||||
// {"Spec", "podSpec", false},
|
||||
{
|
||||
name: "long_json_name",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "Spec",
|
||||
Tags: `json:"podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"Spec"},
|
||||
},
|
||||
// {"JSONSpec", "jsonSpec", true},
|
||||
{
|
||||
name: "acronym",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "JSONSpec",
|
||||
Tags: `json:"jsonSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"JSONSpec", "jsonspec", false},
|
||||
{
|
||||
name: "acronym_invalid",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "JSONSpec",
|
||||
Tags: `json:"jsonspec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"JSONSpec"},
|
||||
},
|
||||
// {"HTTPJSONSpec", "httpJSONSpec", true},
|
||||
{
|
||||
name: "multiple_acronym",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "HTTPJSONSpec",
|
||||
Tags: `json:"httpJSONSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// // NOTE: this validator cannot tell two sequential all-capital words from one word,
|
||||
// // therefore the case below is also considered matched.
|
||||
// {"HTTPJSONSpec", "httpjsonSpec", true},
|
||||
{
|
||||
name: "multiple_acronym_as_one",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "HTTPJSONSpec",
|
||||
Tags: `json:"httpjsonSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// NOTE: JSON tags in jsonTagBlacklist should skip evaluation
|
||||
{
|
||||
name: "blacklist_tag_dash",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "podSpec",
|
||||
Tags: `json:"-"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"PodSpec", "-", false},
|
||||
{
|
||||
name: "invalid_json_name_dash",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"-,"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"PodSpec"},
|
||||
},
|
||||
// NOTE: JSON names in jsonNameBlacklist should skip evaluation
|
||||
// {"", "", true},
|
||||
{
|
||||
name: "unspecified",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "",
|
||||
Tags: `json:""`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"podSpec", "", true},
|
||||
{
|
||||
name: "blacklist_empty",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "podSpec",
|
||||
Tags: `json:""`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// {"podSpec", "metadata", true},
|
||||
{
|
||||
name: "blacklist_metadata",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "podSpec",
|
||||
Tags: `json:"metadata"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "non_struct",
|
||||
t: &types.Type{
|
||||
Kind: types.Map,
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "no_json_tag",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `podSpec`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"PodSpec"},
|
||||
},
|
||||
// NOTE: this is to expand test coverage
|
||||
// {"S", "s", true},
|
||||
{
|
||||
name: "single_character",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "S",
|
||||
Tags: `json:"s"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
// NOTE: names with disallowed substrings should fail evaluation
|
||||
// {"Pod-Spec", "pod-Spec", false},
|
||||
{
|
||||
name: "disallowed_substring_dash",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "Pod-Spec",
|
||||
Tags: `json:"pod-Spec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"Pod-Spec"},
|
||||
},
|
||||
// {"Pod_Spec", "pod_Spec", false},
|
||||
{
|
||||
name: "disallowed_substring_underscore",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "Pod_Spec",
|
||||
Tags: `json:"pod_Spec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"Pod_Spec"},
|
||||
},
|
||||
}
|
||||
|
||||
n := &NamesMatch{}
|
||||
for _, tc := range tcs {
|
||||
if violations, _ := n.Validate(tc.t); !reflect.DeepEqual(violations, tc.expected) {
|
||||
t.Errorf("unexpected validation result: test name %v, want: %v, got: %v",
|
||||
tc.name, tc.expected, violations)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRuleName tests the Name of API rule. This is to expand test coverage
|
||||
func TestRuleName(t *testing.T) {
|
||||
ruleName := "names_match"
|
||||
n := &NamesMatch{}
|
||||
if n.Name() != ruleName {
|
||||
t.Errorf("unexpected API rule name: want: %v, got: %v", ruleName, n.Name())
|
||||
}
|
||||
}
|
64
vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case.go
generated
vendored
64
vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case.go
generated
vendored
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
// OmitEmptyMatchCase implements APIRule interface.
|
||||
// "omitempty" must appear verbatim (no case variants).
|
||||
type OmitEmptyMatchCase struct{}
|
||||
|
||||
func (n *OmitEmptyMatchCase) Name() string {
|
||||
return "omitempty_match_case"
|
||||
}
|
||||
|
||||
func (n *OmitEmptyMatchCase) Validate(t *types.Type) ([]string, error) {
|
||||
fields := make([]string, 0)
|
||||
|
||||
// Only validate struct type and ignore the rest
|
||||
switch t.Kind {
|
||||
case types.Struct:
|
||||
for _, m := range t.Members {
|
||||
goName := m.Name
|
||||
jsonTag, ok := reflect.StructTag(m.Tags).Lookup("json")
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
parts := strings.Split(jsonTag, ",")
|
||||
if len(parts) < 2 {
|
||||
// no tags other than name
|
||||
continue
|
||||
}
|
||||
if parts[0] == "-" {
|
||||
// not serialized
|
||||
continue
|
||||
}
|
||||
for _, part := range parts[1:] {
|
||||
if strings.EqualFold(part, "omitempty") && part != "omitempty" {
|
||||
fields = append(fields, goName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fields, nil
|
||||
}
|
110
vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case_test.go
generated
vendored
110
vendor/k8s.io/kube-openapi/pkg/generators/rules/omitempty_match_case_test.go
generated
vendored
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 rules
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/gengo/types"
|
||||
)
|
||||
|
||||
func TestOmitEmptyMatchCase(t *testing.T) {
|
||||
tcs := []struct {
|
||||
// name of test case
|
||||
name string
|
||||
t *types.Type
|
||||
|
||||
// expected list of violation fields
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "unserialized",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"-,inline"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "named_omitEmpty",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "OmitEmpty",
|
||||
Tags: `json:"omitEmpty,inline"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "valid",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec,omitempty"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "invalid",
|
||||
t: &types.Type{
|
||||
Kind: types.Struct,
|
||||
Members: []types.Member{
|
||||
types.Member{
|
||||
Name: "PodSpec",
|
||||
Tags: `json:"podSpec,omitEmpty"`,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []string{"PodSpec"},
|
||||
},
|
||||
}
|
||||
|
||||
n := &OmitEmptyMatchCase{}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if violations, _ := n.Validate(tc.t); !reflect.DeepEqual(violations, tc.expected) {
|
||||
t.Errorf("unexpected validation result: want: %v, got: %v", tc.expected, violations)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
272
vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
272
vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
@@ -1,272 +0,0 @@
|
||||
/*
|
||||
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 handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"crypto/sha512"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/ww/goautoneg"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/NYTimes/gziphandler"
|
||||
restful "github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
"github.com/golang/protobuf/proto"
|
||||
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/builder"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
const (
|
||||
jsonExt = ".json"
|
||||
|
||||
mimeJson = "application/json"
|
||||
// TODO(mehdy): change @68f4ded to a version tag when gnostic add version tags.
|
||||
mimePb = "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf"
|
||||
mimePbGz = "application/x-gzip"
|
||||
)
|
||||
|
||||
// OpenAPIService is the service responsible for serving OpenAPI spec. It has
|
||||
// the ability to safely change the spec while serving it.
|
||||
type OpenAPIService struct {
|
||||
// rwMutex protects All members of this service.
|
||||
rwMutex sync.RWMutex
|
||||
|
||||
lastModified time.Time
|
||||
|
||||
specBytes []byte
|
||||
specPb []byte
|
||||
specPbGz []byte
|
||||
|
||||
specBytesETag string
|
||||
specPbETag string
|
||||
specPbGzETag string
|
||||
}
|
||||
|
||||
func init() {
|
||||
mime.AddExtensionType(".json", mimeJson)
|
||||
mime.AddExtensionType(".pb-v1", mimePb)
|
||||
mime.AddExtensionType(".gz", mimePbGz)
|
||||
}
|
||||
|
||||
func computeETag(data []byte) string {
|
||||
return fmt.Sprintf("\"%X\"", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
|
||||
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
|
||||
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
|
||||
//
|
||||
// BuildAndRegisterOpenAPIService builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIService.
|
||||
func BuildAndRegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
spec, err := builder.BuildOpenAPISpec(webServices, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RegisterOpenAPIService(spec, servePath, handler)
|
||||
}
|
||||
|
||||
// NOTE: [DEPRECATION] We will announce deprecation for format-separated endpoints for OpenAPI spec,
|
||||
// and switch to a single /openapi/v2 endpoint in Kubernetes 1.10. The design doc and deprecation process
|
||||
// are tracked at: https://docs.google.com/document/d/19lEqE9lc4yHJ3WJAJxS_G7TcORIJXGHyq3wpwcH28nU.
|
||||
//
|
||||
// RegisterOpenAPIService registers a handler to provide access to provided swagger spec.
|
||||
// Note: servePath should end with ".json" as the RegisterOpenAPIService assume it is serving a
|
||||
// json file and will also serve .pb and .gz files.
|
||||
func RegisterOpenAPIService(openapiSpec *spec.Swagger, servePath string, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
if !strings.HasSuffix(servePath, jsonExt) {
|
||||
return nil, fmt.Errorf("serving path must end with \"%s\"", jsonExt)
|
||||
}
|
||||
|
||||
servePathBase := strings.TrimSuffix(servePath, jsonExt)
|
||||
|
||||
o := OpenAPIService{}
|
||||
if err := o.UpdateSpec(openapiSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
ext string
|
||||
getDataAndETag func() ([]byte, string, time.Time)
|
||||
}
|
||||
|
||||
files := []fileInfo{
|
||||
{".json", o.getSwaggerBytes},
|
||||
{"-2.0.0.json", o.getSwaggerBytes},
|
||||
{"-2.0.0.pb-v1", o.getSwaggerPbBytes},
|
||||
{"-2.0.0.pb-v1.gz", o.getSwaggerPbGzBytes},
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
path := servePathBase + file.ext
|
||||
getDataAndETag := file.getDataAndETag
|
||||
handler.Handle(path, gziphandler.GzipHandler(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
data, etag, lastModified := getDataAndETag()
|
||||
w.Header().Set("Etag", etag)
|
||||
|
||||
// ServeContent will take care of caching using eTag.
|
||||
http.ServeContent(w, r, path, lastModified, bytes.NewReader(data))
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getSwaggerBytes() ([]byte, string, time.Time) {
|
||||
o.rwMutex.RLock()
|
||||
defer o.rwMutex.RUnlock()
|
||||
return o.specBytes, o.specBytesETag, o.lastModified
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getSwaggerPbBytes() ([]byte, string, time.Time) {
|
||||
o.rwMutex.RLock()
|
||||
defer o.rwMutex.RUnlock()
|
||||
return o.specPb, o.specPbETag, o.lastModified
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) getSwaggerPbGzBytes() ([]byte, string, time.Time) {
|
||||
o.rwMutex.RLock()
|
||||
defer o.rwMutex.RUnlock()
|
||||
return o.specPbGz, o.specPbGzETag, o.lastModified
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateSpec(openapiSpec *spec.Swagger) (err error) {
|
||||
specBytes, err := json.MarshalIndent(openapiSpec, " ", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
specPb, err := toProtoBinary(specBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
specPbGz := toGzip(specPb)
|
||||
|
||||
specBytesETag := computeETag(specBytes)
|
||||
specPbETag := computeETag(specPb)
|
||||
specPbGzETag := computeETag(specPbGz)
|
||||
|
||||
lastModified := time.Now()
|
||||
|
||||
o.rwMutex.Lock()
|
||||
defer o.rwMutex.Unlock()
|
||||
|
||||
o.specBytes = specBytes
|
||||
o.specPb = specPb
|
||||
o.specPbGz = specPbGz
|
||||
o.specBytesETag = specBytesETag
|
||||
o.specPbETag = specPbETag
|
||||
o.specPbGzETag = specPbGzETag
|
||||
o.lastModified = lastModified
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toProtoBinary(spec []byte) ([]byte, error) {
|
||||
var info yaml.MapSlice
|
||||
err := yaml.Unmarshal(spec, &info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
document, err := openapi_v2.NewDocument(info, compiler.NewContext("$root", nil))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(document)
|
||||
}
|
||||
|
||||
func toGzip(data []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
zw := gzip.NewWriter(&buf)
|
||||
zw.Write(data)
|
||||
zw.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec.
|
||||
func RegisterOpenAPIVersionedService(openapiSpec *spec.Swagger, servePath string, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
o := OpenAPIService{}
|
||||
if err := o.UpdateSpec(openapiSpec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
GetDataAndETag func() ([]byte, string, time.Time)
|
||||
}{
|
||||
{"application", "json", o.getSwaggerBytes},
|
||||
{"application", "com.github.proto-openapi.spec.v2@v1.0+protobuf", o.getSwaggerPbBytes},
|
||||
}
|
||||
|
||||
handler.Handle(servePath, gziphandler.GzipHandler(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
|
||||
// serve the first matching media type in the sorted clause list
|
||||
data, etag, lastModified := accepts.GetDataAndETag()
|
||||
w.Header().Set("Etag", etag)
|
||||
// ServeContent will take care of caching using eTag.
|
||||
http.ServeContent(w, r, servePath, lastModified, bytes.NewReader(data))
|
||||
return
|
||||
}
|
||||
}
|
||||
// Return 406 for not acceptable format
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}),
|
||||
))
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
func BuildAndRegisterOpenAPIVersionedService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
spec, err := builder.BuildOpenAPISpec(webServices, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RegisterOpenAPIVersionedService(spec, servePath, handler)
|
||||
}
|
89
vendor/k8s.io/kube-openapi/pkg/handler/handler_test.go
generated
vendored
89
vendor/k8s.io/kube-openapi/pkg/handler/handler_test.go
generated
vendored
@@ -1,89 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
)
|
||||
|
||||
var returnedSwagger = []byte(`{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "Kubernetes",
|
||||
"version": "v1.11.0"
|
||||
}}`)
|
||||
|
||||
func TestRegisterOpenAPIVersionedService(t *testing.T) {
|
||||
var s spec.Swagger
|
||||
err := s.UnmarshalJSON(returnedSwagger)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error in unmarshalling SwaggerJSON: %v", err)
|
||||
}
|
||||
|
||||
returnedJSON, err := json.MarshalIndent(s, " ", " ")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error in preparing returnedJSON: %v", err)
|
||||
}
|
||||
returnedPb, err := toProtoBinary(returnedJSON)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error in preparing returnedPb: %v", err)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
_, err = RegisterOpenAPIVersionedService(&s, "/openapi/v2", mux)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error in register OpenAPI versioned service: %v", err)
|
||||
}
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
client := server.Client()
|
||||
|
||||
tcs := []struct {
|
||||
acceptHeader string
|
||||
respStatus int
|
||||
respBody []byte
|
||||
}{
|
||||
{"", 200, returnedJSON},
|
||||
{"*/*", 200, returnedJSON},
|
||||
{"application/*", 200, returnedJSON},
|
||||
{"application/json", 200, returnedJSON},
|
||||
{"test/test", 406, []byte{}},
|
||||
{"application/test", 406, []byte{}},
|
||||
{"application/test, */*", 200, returnedJSON},
|
||||
{"application/test, application/json", 200, returnedJSON},
|
||||
{"application/com.github.proto-openapi.spec.v2@v1.0+protobuf", 200, returnedPb},
|
||||
{"application/json, application/com.github.proto-openapi.spec.v2@v1.0+protobuf", 200, returnedJSON},
|
||||
{"application/com.github.proto-openapi.spec.v2@v1.0+protobuf, application/json", 200, returnedPb},
|
||||
{"application/com.github.proto-openapi.spec.v2@v1.0+protobuf; q=0.5, application/json", 200, returnedJSON},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
req, err := http.NewRequest("GET", server.URL+"/openapi/v2", nil)
|
||||
if err != nil {
|
||||
t.Errorf("Accept: %v: Unexpected error in creating new request: %v", tc.acceptHeader, err)
|
||||
}
|
||||
|
||||
req.Header.Add("Accept", tc.acceptHeader)
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
t.Errorf("Accept: %v: Unexpected error in serving HTTP request: %v", tc.acceptHeader, err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != tc.respStatus {
|
||||
t.Errorf("Accept: %v: Unexpected response status code, want: %v, got: %v", tc.acceptHeader, tc.respStatus, resp.StatusCode)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Accept: %v: Unexpected error in reading response body: %v", tc.acceptHeader, err)
|
||||
}
|
||||
if !reflect.DeepEqual(body, tc.respBody) {
|
||||
t.Errorf("Accept: %v: Response body mismatches, want: %v, got: %v", tc.acceptHeader, tc.respBody, body)
|
||||
}
|
||||
}
|
||||
}
|
140
vendor/k8s.io/kube-openapi/pkg/idl/doc.go
generated
vendored
140
vendor/k8s.io/kube-openapi/pkg/idl/doc.go
generated
vendored
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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.
|
||||
*/
|
||||
|
||||
// The IDL package describes comment directives that may be applied to
|
||||
// API types and fields.
|
||||
package idl
|
||||
|
||||
// ListType annotates a list to further describe its topology. It may
|
||||
// have 3 possible values: "atomic", "map", or "set". Note that there is
|
||||
// no default, and the generation step will fail if a list is found that
|
||||
// is missing the tag.
|
||||
//
|
||||
// This tag MUST only be used on lists, or the generation step will
|
||||
// fail.
|
||||
//
|
||||
// Atomic
|
||||
//
|
||||
// Example:
|
||||
// +listType=atomic
|
||||
//
|
||||
// Atomic lists will be entirely replaced when updated. This tag may be
|
||||
// used on any type of list (struct, scalar, ...).
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-list-type": "atomic"
|
||||
//
|
||||
// Map
|
||||
//
|
||||
// Example:
|
||||
// +listType=map
|
||||
//
|
||||
// These lists are like maps in that their elements have a non-index key
|
||||
// used to identify them. Order is preserved upon merge. Using the map
|
||||
// tag on a list with non-struct elements will result in an error during
|
||||
// the generation step.
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-list-type": "map"
|
||||
//
|
||||
// Set
|
||||
//
|
||||
// Example:
|
||||
// +listType=set
|
||||
//
|
||||
// Sets are lists that must not have multiple times the same value. Each
|
||||
// value must be a scalar (or another atomic type).
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-list-type": "set"
|
||||
type ListType string
|
||||
|
||||
// ListMapKey annotates map lists by specifying the key used as the index of the map.
|
||||
//
|
||||
// This tag MUST only be used on lists that have the listType=map
|
||||
// attribute, or the generation step will fail. Also, the value
|
||||
// specified for this attribute must be a scalar typed field of the
|
||||
// child structure (no nesting is supported).
|
||||
//
|
||||
// An example of how this can be used is shown in the ListType (map) example.
|
||||
//
|
||||
// Example:
|
||||
// +listMapKey=name
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-list-map-key": "name"
|
||||
type ListMapKey string
|
||||
|
||||
// MapType annotates a map to further describe its topology. It may
|
||||
// have only one value: "atomic". Atomic means that the entire map is
|
||||
// considered as a whole, rather than as distinct values.
|
||||
//
|
||||
// By default, a map will be considered as a set of distinct values that
|
||||
// can be updated individually. This default WILL NOT generate any
|
||||
// openapi extension, as this will also be interpreted as the default
|
||||
// behavior in the openapi definition.
|
||||
//
|
||||
// This tag MUST only be used on maps, or the generation step will fail.
|
||||
//
|
||||
// Atomic
|
||||
//
|
||||
// Example:
|
||||
// +mapType=atomic
|
||||
//
|
||||
// Atomic maps will be entirely replaced when updated. This tag may be
|
||||
// used on any map.
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-map-type": "atomic"
|
||||
type MapType string
|
||||
|
||||
// OpenAPIGen needs to be described.
|
||||
type OpenAPIGen string
|
||||
|
||||
// Optional needs to be described.
|
||||
type Optional string
|
||||
|
||||
// PatchMergeKey needs to be described.
|
||||
type PatchMergeKey string
|
||||
|
||||
// PatchStrategy needs to be described.
|
||||
type PatchStrategy string
|
||||
|
||||
// StructType annotates a struct to further describe its topology. It may
|
||||
// have only one value: "atomic". Atomic means that the entire struct is
|
||||
// considered as a whole, rather than as distinct values.
|
||||
//
|
||||
// By default, a struct will be considered as a set of distinct values that
|
||||
// can be updated individually. This default WILL NOT generate any
|
||||
// openapi extension, as this will also be interpreted as the default
|
||||
// behavior in the openapi definition.
|
||||
//
|
||||
// This tag MUST only be used on structs, or the generation step will fail.
|
||||
//
|
||||
// Atomic
|
||||
//
|
||||
// Example:
|
||||
// +structType=atomic
|
||||
//
|
||||
// Atomic structs will be entirely replaced when updated. This tag may be
|
||||
// used on any struct.
|
||||
//
|
||||
// Using this tag will generate the following OpenAPI extension:
|
||||
// "x-kubernetes-struct-type": "atomic"
|
||||
type StructType string
|
||||
|
||||
// Union is TBD.
|
||||
type Union string
|
56
vendor/k8s.io/kube-openapi/pkg/idl/listtype_test.go
generated
vendored
56
vendor/k8s.io/kube-openapi/pkg/idl/listtype_test.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 idl_test
|
||||
|
||||
// This example shows how to use the listType map attribute and how to
|
||||
// specify a key to identify elements of the list. The listMapKey
|
||||
// attribute is used to specify that Name is the key of the map.
|
||||
func ExampleListType_map() {
|
||||
type SomeStruct struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
type SomeAPI struct {
|
||||
// +listType=map
|
||||
// +listMapKey=name
|
||||
elements []SomeStruct
|
||||
}
|
||||
}
|
||||
|
||||
// This example shows how to use the listType set attribute to specify
|
||||
// that this list should be treated as a set: items in the list can't be
|
||||
// duplicated.
|
||||
func ExampleListType_set() {
|
||||
type SomeAPI struct {
|
||||
// +listType=set
|
||||
keys []string
|
||||
}
|
||||
}
|
||||
|
||||
// This example shows how to use the listType atomic attribute to
|
||||
// specify that this list should be treated as a whole.
|
||||
func ExampleListType_atomic() {
|
||||
type SomeStruct struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
type SomeAPI struct {
|
||||
// +listType=atomic
|
||||
elements []SomeStruct
|
||||
}
|
||||
}
|
26
vendor/k8s.io/kube-openapi/pkg/idl/maptype_test.go
generated
vendored
26
vendor/k8s.io/kube-openapi/pkg/idl/maptype_test.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 idl_test
|
||||
|
||||
// This example shows how to use the mapType atomic attribute to
|
||||
// specify that this map should be treated as a whole.
|
||||
func ExampleMapType_atomic() {
|
||||
type SomeAPI struct {
|
||||
// +mapType=atomic
|
||||
elements map[string]string
|
||||
}
|
||||
}
|
30
vendor/k8s.io/kube-openapi/pkg/idl/structtype_test.go
generated
vendored
30
vendor/k8s.io/kube-openapi/pkg/idl/structtype_test.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 idl_test
|
||||
|
||||
// This example shows how to use the structType atomic attribute to
|
||||
// specify that this struct should be treated as a whole.
|
||||
func ExampleStructType_atomic() {
|
||||
type SomeStruct struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
type SomeAPI struct {
|
||||
// +structType=atomic
|
||||
elements SomeStruct
|
||||
}
|
||||
}
|
242
vendor/k8s.io/kube-openapi/pkg/schemaconv/smd.go
generated
vendored
242
vendor/k8s.io/kube-openapi/pkg/schemaconv/smd.go
generated
vendored
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
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 schemaconv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"sigs.k8s.io/structured-merge-diff/schema"
|
||||
)
|
||||
|
||||
// ToSchema converts openapi definitions into a schema suitable for structured
|
||||
// merge (i.e. kubectl apply v2).
|
||||
func ToSchema(models proto.Models) (*schema.Schema, error) {
|
||||
c := convert{
|
||||
input: models,
|
||||
output: &schema.Schema{},
|
||||
}
|
||||
if err := c.convertAll(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c.output, nil
|
||||
}
|
||||
|
||||
type convert struct {
|
||||
input proto.Models
|
||||
output *schema.Schema
|
||||
|
||||
currentName string
|
||||
current *schema.Atom
|
||||
errorMessages []string
|
||||
}
|
||||
|
||||
func (c *convert) push(name string, a *schema.Atom) *convert {
|
||||
return &convert{
|
||||
input: c.input,
|
||||
output: c.output,
|
||||
currentName: name,
|
||||
current: a,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) top() *schema.Atom { return c.current }
|
||||
|
||||
func (c *convert) pop(c2 *convert) {
|
||||
c.errorMessages = append(c.errorMessages, c2.errorMessages...)
|
||||
}
|
||||
|
||||
func (c *convert) convertAll() error {
|
||||
for _, name := range c.input.ListModels() {
|
||||
model := c.input.LookupModel(name)
|
||||
c.insertTypeDef(name, model)
|
||||
}
|
||||
if len(c.errorMessages) > 0 {
|
||||
return errors.New(strings.Join(c.errorMessages, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *convert) reportError(format string, args ...interface{}) {
|
||||
c.errorMessages = append(c.errorMessages,
|
||||
c.currentName+": "+fmt.Sprintf(format, args...),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *convert) insertTypeDef(name string, model proto.Schema) {
|
||||
def := schema.TypeDef{
|
||||
Name: name,
|
||||
}
|
||||
c2 := c.push(name, &def.Atom)
|
||||
model.Accept(c2)
|
||||
c.pop(c2)
|
||||
if def.Atom == (schema.Atom{}) {
|
||||
// This could happen if there were a top-level reference.
|
||||
return
|
||||
}
|
||||
c.output.Types = append(c.output.Types, def)
|
||||
}
|
||||
|
||||
func (c *convert) makeRef(model proto.Schema) schema.TypeRef {
|
||||
var tr schema.TypeRef
|
||||
if r, ok := model.(*proto.Ref); ok {
|
||||
// reference a named type
|
||||
_, n := path.Split(r.Reference())
|
||||
tr.NamedType = &n
|
||||
} else {
|
||||
// compute the type inline
|
||||
c2 := c.push("inlined in "+c.currentName, &tr.Inlined)
|
||||
model.Accept(c2)
|
||||
c.pop(c2)
|
||||
|
||||
if tr == (schema.TypeRef{}) {
|
||||
// emit warning?
|
||||
tr.Inlined.Untyped = &schema.Untyped{}
|
||||
}
|
||||
}
|
||||
return tr
|
||||
}
|
||||
|
||||
func (c *convert) VisitKind(k *proto.Kind) {
|
||||
a := c.top()
|
||||
a.Struct = &schema.Struct{}
|
||||
for _, name := range k.FieldOrder {
|
||||
member := k.Fields[name]
|
||||
tr := c.makeRef(member)
|
||||
a.Struct.Fields = append(a.Struct.Fields, schema.StructField{
|
||||
Name: name,
|
||||
Type: tr,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: Get element relationship when we start adding it to the spec.
|
||||
}
|
||||
|
||||
func toStringSlice(o interface{}) (out []string, ok bool) {
|
||||
switch t := o.(type) {
|
||||
case []interface{}:
|
||||
for _, v := range t {
|
||||
switch vt := v.(type) {
|
||||
case string:
|
||||
out = append(out, vt)
|
||||
}
|
||||
}
|
||||
return out, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (c *convert) VisitArray(a *proto.Array) {
|
||||
atom := c.top()
|
||||
atom.List = &schema.List{
|
||||
ElementRelationship: schema.Atomic,
|
||||
}
|
||||
l := atom.List
|
||||
l.ElementType = c.makeRef(a.SubType)
|
||||
|
||||
ext := a.GetExtensions()
|
||||
|
||||
if val, ok := ext["x-kubernetes-list-type"]; ok {
|
||||
if val == "atomic" {
|
||||
l.ElementRelationship = schema.Atomic
|
||||
} else if val == "set" {
|
||||
l.ElementRelationship = schema.Associative
|
||||
} else if val == "map" {
|
||||
l.ElementRelationship = schema.Associative
|
||||
if keys, ok := ext["x-kubernetes-list-map-keys"]; ok {
|
||||
if keyNames, ok := toStringSlice(keys); ok {
|
||||
l.Keys = keyNames
|
||||
} else {
|
||||
c.reportError("uninterpreted map keys: %#v", keys)
|
||||
}
|
||||
} else {
|
||||
c.reportError("missing map keys")
|
||||
}
|
||||
} else {
|
||||
c.reportError("unknown list type %v", val)
|
||||
l.ElementRelationship = schema.Atomic
|
||||
}
|
||||
} else if val, ok := ext["x-kubernetes-patch-strategy"]; ok {
|
||||
if val == "merge" || val == "merge,retainKeys" {
|
||||
l.ElementRelationship = schema.Associative
|
||||
if key, ok := ext["x-kubernetes-patch-merge-key"]; ok {
|
||||
if keyName, ok := key.(string); ok {
|
||||
l.Keys = []string{keyName}
|
||||
} else {
|
||||
c.reportError("uninterpreted merge key: %#v", key)
|
||||
}
|
||||
} else {
|
||||
// It's not an error for this to be absent, it
|
||||
// means it's a set.
|
||||
}
|
||||
} else if val == "retainKeys" {
|
||||
} else {
|
||||
c.reportError("unknown patch strategy %v", val)
|
||||
l.ElementRelationship = schema.Atomic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitMap(m *proto.Map) {
|
||||
a := c.top()
|
||||
a.Map = &schema.Map{}
|
||||
a.Map.ElementType = c.makeRef(m.SubType)
|
||||
|
||||
// TODO: Get element relationship when we start putting it into the
|
||||
// spec.
|
||||
}
|
||||
|
||||
func (c *convert) VisitPrimitive(p *proto.Primitive) {
|
||||
a := c.top()
|
||||
ptr := func(s schema.Scalar) *schema.Scalar { return &s }
|
||||
switch p.Type {
|
||||
case proto.Integer:
|
||||
a.Scalar = ptr(schema.Numeric)
|
||||
case proto.Number:
|
||||
a.Scalar = ptr(schema.Numeric)
|
||||
case proto.String:
|
||||
switch p.Format {
|
||||
case "":
|
||||
a.Scalar = ptr(schema.String)
|
||||
case "byte":
|
||||
// byte really means []byte and is encoded as a string.
|
||||
a.Scalar = ptr(schema.String)
|
||||
case "int-or-string":
|
||||
a.Untyped = &schema.Untyped{}
|
||||
case "date-time":
|
||||
a.Untyped = &schema.Untyped{}
|
||||
default:
|
||||
a.Untyped = &schema.Untyped{}
|
||||
}
|
||||
case proto.Boolean:
|
||||
a.Scalar = ptr(schema.Boolean)
|
||||
default:
|
||||
a.Untyped = &schema.Untyped{}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *convert) VisitArbitrary(a *proto.Arbitrary) {
|
||||
c.top().Untyped = &schema.Untyped{}
|
||||
}
|
||||
|
||||
func (c *convert) VisitReference(proto.Reference) {
|
||||
// Do nothing, we handle references specially
|
||||
}
|
68
vendor/k8s.io/kube-openapi/pkg/schemaconv/smd_test.go
generated
vendored
68
vendor/k8s.io/kube-openapi/pkg/schemaconv/smd_test.go
generated
vendored
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
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 schemaconv
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
prototesting "k8s.io/kube-openapi/pkg/util/proto/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
openAPIPath = filepath.Join("testdata", "swagger.json")
|
||||
fakeSchema = prototesting.Fake{Path: openAPIPath}
|
||||
expectedNewSchemaPath = filepath.Join("testdata", "new-schema.yaml")
|
||||
)
|
||||
|
||||
func TestToSchema(t *testing.T) {
|
||||
s, err := fakeSchema.OpenAPISchema()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
models, err := proto.NewOpenAPIData(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns, err := ToSchema(models)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := yaml.Marshal(ns)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expect, err := ioutil.ReadFile(expectedNewSchemaPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to read golden data file %q: %v", expectedNewSchemaPath, err)
|
||||
}
|
||||
|
||||
if string(expect) != string(got) {
|
||||
t.Errorf("Computed schema did not match %q.", expectedNewSchemaPath)
|
||||
t.Logf("To recompute this file, run:\n\tgo run ./cmd/openapi2smd/openapi2smd.go < %q > %q",
|
||||
filepath.Join("pkg", "schemaconv", openAPIPath),
|
||||
filepath.Join("pkg", "schemaconv", expectedNewSchemaPath),
|
||||
)
|
||||
t.Log("You can then use `git diff` to see the changes.")
|
||||
}
|
||||
}
|
10141
vendor/k8s.io/kube-openapi/pkg/schemaconv/testdata/new-schema.yaml
generated
vendored
10141
vendor/k8s.io/kube-openapi/pkg/schemaconv/testdata/new-schema.yaml
generated
vendored
File diff suppressed because it is too large
Load Diff
94973
vendor/k8s.io/kube-openapi/pkg/schemaconv/testdata/swagger.json
generated
vendored
94973
vendor/k8s.io/kube-openapi/pkg/schemaconv/testdata/swagger.json
generated
vendored
File diff suppressed because it is too large
Load Diff
49
vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go
generated
vendored
49
vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_suite_test.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
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 proto_test
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/config"
|
||||
. "github.com/onsi/ginkgo/types"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOpenapi(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecsWithDefaultAndCustomReporters(t, "Openapi Suite", []Reporter{newlineReporter{}})
|
||||
}
|
||||
|
||||
// Print a newline after the default newlineReporter due to issue
|
||||
// https://github.com/jstemmer/go-junit-report/issues/31
|
||||
type newlineReporter struct{}
|
||||
|
||||
func (newlineReporter) SpecSuiteWillBegin(config GinkgoConfigType, summary *SuiteSummary) {}
|
||||
|
||||
func (newlineReporter) BeforeSuiteDidRun(setupSummary *SetupSummary) {}
|
||||
|
||||
func (newlineReporter) AfterSuiteDidRun(setupSummary *SetupSummary) {}
|
||||
|
||||
func (newlineReporter) SpecWillRun(specSummary *SpecSummary) {}
|
||||
|
||||
func (newlineReporter) SpecDidComplete(specSummary *SpecSummary) {}
|
||||
|
||||
// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:"
|
||||
func (newlineReporter) SpecSuiteDidEnd(summary *SuiteSummary) { fmt.Printf("\n") }
|
265
vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go
generated
vendored
265
vendor/k8s.io/kube-openapi/pkg/util/proto/openapi_test.go
generated
vendored
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
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 proto_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kube-openapi/pkg/util/proto/testing"
|
||||
)
|
||||
|
||||
var fakeSchema = testing.Fake{Path: filepath.Join("testdata", "swagger.json")}
|
||||
var fakeSchemaNext = testing.Fake{Path: filepath.Join("testdata", "swagger_next.json")}
|
||||
|
||||
var _ = Describe("Reading apps/v1beta1/Deployment from v1.8 openAPIData", func() {
|
||||
var models proto.Models
|
||||
BeforeEach(func() {
|
||||
s, err := fakeSchema.OpenAPISchema()
|
||||
Expect(err).To(BeNil())
|
||||
models, err = proto.NewOpenAPIData(s)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
model := "io.k8s.api.apps.v1beta1.Deployment"
|
||||
var schema proto.Schema
|
||||
It("should lookup the Schema by its model name", func() {
|
||||
schema = models.LookupModel(model)
|
||||
Expect(schema).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var deployment *proto.Kind
|
||||
It("should be a Kind", func() {
|
||||
deployment = schema.(*proto.Kind)
|
||||
Expect(deployment).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should have a path", func() {
|
||||
Expect(deployment.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment"}))
|
||||
})
|
||||
|
||||
It("should have a kind key of type string", func() {
|
||||
Expect(deployment.Fields).To(HaveKey("kind"))
|
||||
key := deployment.Fields["kind"].(*proto.Primitive)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Type).To(Equal("string"))
|
||||
Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".kind"}))
|
||||
})
|
||||
|
||||
It("should have a apiVersion key of type string", func() {
|
||||
Expect(deployment.Fields).To(HaveKey("apiVersion"))
|
||||
key := deployment.Fields["apiVersion"].(*proto.Primitive)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Type).To(Equal("string"))
|
||||
Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".apiVersion"}))
|
||||
})
|
||||
|
||||
It("should have a metadata key of type Reference", func() {
|
||||
Expect(deployment.Fields).To(HaveKey("metadata"))
|
||||
key := deployment.Fields["metadata"].(proto.Reference)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Reference()).To(Equal("io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"))
|
||||
subSchema := key.SubSchema().(*proto.Kind)
|
||||
Expect(subSchema).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var status *proto.Kind
|
||||
It("should have a status key of type Reference", func() {
|
||||
Expect(deployment.Fields).To(HaveKey("status"))
|
||||
key := deployment.Fields["status"].(proto.Reference)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentStatus"))
|
||||
status = key.SubSchema().(*proto.Kind)
|
||||
Expect(status).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should have a valid DeploymentStatus", func() {
|
||||
By("having availableReplicas key")
|
||||
Expect(status.Fields).To(HaveKey("availableReplicas"))
|
||||
replicas := status.Fields["availableReplicas"].(*proto.Primitive)
|
||||
Expect(replicas).ToNot(BeNil())
|
||||
Expect(replicas.Type).To(Equal("integer"))
|
||||
|
||||
By("having conditions key")
|
||||
Expect(status.Fields).To(HaveKey("conditions"))
|
||||
conditions := status.Fields["conditions"].(*proto.Array)
|
||||
Expect(conditions).ToNot(BeNil())
|
||||
Expect(conditions.GetName()).To(Equal(`Array of Reference to "io.k8s.api.apps.v1beta1.DeploymentCondition"`))
|
||||
Expect(conditions.GetExtensions()).To(Equal(map[string]interface{}{
|
||||
"x-kubernetes-patch-merge-key": "type",
|
||||
"x-kubernetes-patch-strategy": "merge",
|
||||
}))
|
||||
condition := conditions.SubType.(proto.Reference)
|
||||
Expect(condition.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentCondition"))
|
||||
})
|
||||
|
||||
var spec *proto.Kind
|
||||
It("should have a spec key of type Reference", func() {
|
||||
Expect(deployment.Fields).To(HaveKey("spec"))
|
||||
key := deployment.Fields["spec"].(proto.Reference)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentSpec"))
|
||||
spec = key.SubSchema().(*proto.Kind)
|
||||
Expect(spec).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should have a spec with no gvk", func() {
|
||||
_, found := spec.GetExtensions()["x-kubernetes-group-version-kind"]
|
||||
Expect(found).To(BeFalse())
|
||||
})
|
||||
|
||||
It("should have a spec with a PodTemplateSpec sub-field", func() {
|
||||
Expect(spec.Fields).To(HaveKey("template"))
|
||||
key := spec.Fields["template"].(proto.Reference)
|
||||
Expect(key).ToNot(BeNil())
|
||||
Expect(key.Reference()).To(Equal("io.k8s.api.core.v1.PodTemplateSpec"))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Reading apps/v1beta1/Deployment from v1.11 openAPIData", func() {
|
||||
var models proto.Models
|
||||
BeforeEach(func() {
|
||||
s, err := fakeSchemaNext.OpenAPISchema()
|
||||
Expect(err).To(BeNil())
|
||||
models, err = proto.NewOpenAPIData(s)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
model := "io.k8s.api.apps.v1beta1.Deployment"
|
||||
var schema proto.Schema
|
||||
It("should lookup the Schema by its model name", func() {
|
||||
schema = models.LookupModel(model)
|
||||
Expect(schema).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var deployment *proto.Kind
|
||||
It("should be a Kind", func() {
|
||||
deployment = schema.(*proto.Kind)
|
||||
Expect(deployment).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Reading apps/v1beta1/ControllerRevision from v1.11 openAPIData", func() {
|
||||
var models proto.Models
|
||||
BeforeEach(func() {
|
||||
s, err := fakeSchemaNext.OpenAPISchema()
|
||||
Expect(err).To(BeNil())
|
||||
models, err = proto.NewOpenAPIData(s)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
model := "io.k8s.api.apps.v1beta1.ControllerRevision"
|
||||
var schema proto.Schema
|
||||
It("should lookup the Schema by its model name", func() {
|
||||
schema = models.LookupModel(model)
|
||||
Expect(schema).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var cr *proto.Kind
|
||||
It("data property should be map[string]Arbitrary", func() {
|
||||
cr = schema.(*proto.Kind)
|
||||
Expect(cr).ToNot(BeNil())
|
||||
Expect(cr.Fields).To(HaveKey("data"))
|
||||
|
||||
data := cr.Fields["data"].(*proto.Map)
|
||||
Expect(data).ToNot(BeNil())
|
||||
Expect(data.GetName()).To(Equal("Map of Arbitrary value (primitive, object or array)"))
|
||||
Expect(data.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.ControllerRevision", ".data"}))
|
||||
|
||||
arbitrary := data.SubType.(*proto.Arbitrary)
|
||||
Expect(arbitrary).ToNot(BeNil())
|
||||
Expect(arbitrary.GetName()).To(Equal("Arbitrary value (primitive, object or array)"))
|
||||
Expect(arbitrary.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.ControllerRevision", ".data"}))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Reading authorization.k8s.io/v1/SubjectAccessReview from openAPIData", func() {
|
||||
var models proto.Models
|
||||
BeforeEach(func() {
|
||||
s, err := fakeSchema.OpenAPISchema()
|
||||
Expect(err).To(BeNil())
|
||||
models, err = proto.NewOpenAPIData(s)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
model := "io.k8s.api.authorization.v1.LocalSubjectAccessReview"
|
||||
var schema proto.Schema
|
||||
It("should lookup the Schema by its model", func() {
|
||||
schema = models.LookupModel(model)
|
||||
Expect(schema).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var sarspec *proto.Kind
|
||||
It("should be a Kind and have a spec", func() {
|
||||
sar := schema.(*proto.Kind)
|
||||
Expect(sar).ToNot(BeNil())
|
||||
Expect(sar.Fields).To(HaveKey("spec"))
|
||||
specRef := sar.Fields["spec"].(proto.Reference)
|
||||
Expect(specRef).ToNot(BeNil())
|
||||
Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec"))
|
||||
sarspec = specRef.SubSchema().(*proto.Kind)
|
||||
Expect(sarspec).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("should have a valid SubjectAccessReviewSpec", func() {
|
||||
Expect(sarspec.Fields).To(HaveKey("extra"))
|
||||
extra := sarspec.Fields["extra"].(*proto.Map)
|
||||
Expect(extra).ToNot(BeNil())
|
||||
Expect(extra.GetName()).To(Equal("Map of Array of string"))
|
||||
Expect(extra.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
|
||||
array := extra.SubType.(*proto.Array)
|
||||
Expect(array).ToNot(BeNil())
|
||||
Expect(array.GetName()).To(Equal("Array of string"))
|
||||
Expect(array.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
|
||||
str := array.SubType.(*proto.Primitive)
|
||||
Expect(str).ToNot(BeNil())
|
||||
Expect(str.Type).To(Equal("string"))
|
||||
Expect(str.GetName()).To(Equal("string"))
|
||||
Expect(str.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Path", func() {
|
||||
It("can be created by NewPath", func() {
|
||||
path := proto.NewPath("key")
|
||||
Expect(path.String()).To(Equal("key"))
|
||||
})
|
||||
It("can create and print complex paths", func() {
|
||||
key := proto.NewPath("key")
|
||||
array := key.ArrayPath(12)
|
||||
field := array.FieldPath("subKey")
|
||||
|
||||
Expect(field.String()).To(Equal("key[12].subKey"))
|
||||
})
|
||||
It("has a length", func() {
|
||||
key := proto.NewPath("key")
|
||||
array := key.ArrayPath(12)
|
||||
field := array.FieldPath("subKey")
|
||||
|
||||
Expect(field.Len()).To(Equal(3))
|
||||
})
|
||||
It("can look like an array", func() {
|
||||
key := proto.NewPath("key")
|
||||
array := key.ArrayPath(12)
|
||||
field := array.FieldPath("subKey")
|
||||
|
||||
Expect(field.Get()).To(Equal([]string{"key", "[12]", ".subKey"}))
|
||||
})
|
||||
})
|
6375
vendor/k8s.io/kube-openapi/pkg/util/proto/testdata/swagger.json
generated
vendored
6375
vendor/k8s.io/kube-openapi/pkg/util/proto/testdata/swagger.json
generated
vendored
File diff suppressed because it is too large
Load Diff
6574
vendor/k8s.io/kube-openapi/pkg/util/proto/testdata/swagger_next.json
generated
vendored
6574
vendor/k8s.io/kube-openapi/pkg/util/proto/testdata/swagger_next.json
generated
vendored
File diff suppressed because it is too large
Load Diff
68
vendor/k8s.io/kube-openapi/pkg/util/proto/testing/openapi.go
generated
vendored
68
vendor/k8s.io/kube-openapi/pkg/util/proto/testing/openapi.go
generated
vendored
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
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 testing
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/googleapis/gnostic/OpenAPIv2"
|
||||
"github.com/googleapis/gnostic/compiler"
|
||||
)
|
||||
|
||||
// Fake opens and returns a openapi swagger from a file Path. It will
|
||||
// parse only once and then return the same copy everytime.
|
||||
type Fake struct {
|
||||
Path string
|
||||
|
||||
once sync.Once
|
||||
document *openapi_v2.Document
|
||||
err error
|
||||
}
|
||||
|
||||
// OpenAPISchema returns the openapi document and a potential error.
|
||||
func (f *Fake) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
f.once.Do(func() {
|
||||
_, err := os.Stat(f.Path)
|
||||
if err != nil {
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
spec, err := ioutil.ReadFile(f.Path)
|
||||
if err != nil {
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
var info yaml.MapSlice
|
||||
err = yaml.Unmarshal(spec, &info)
|
||||
if err != nil {
|
||||
f.err = err
|
||||
return
|
||||
}
|
||||
f.document, f.err = openapi_v2.NewDocument(info, compiler.NewContext("$root", nil))
|
||||
})
|
||||
return f.document, f.err
|
||||
}
|
||||
|
||||
type Empty struct{}
|
||||
|
||||
func (Empty) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||
return nil, nil
|
||||
}
|
79
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/errors.go
generated
vendored
79
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/errors.go
generated
vendored
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type errors struct {
|
||||
errors []error
|
||||
}
|
||||
|
||||
func (e *errors) Errors() []error {
|
||||
return e.errors
|
||||
}
|
||||
|
||||
func (e *errors) AppendErrors(err ...error) {
|
||||
e.errors = append(e.errors, err...)
|
||||
}
|
||||
|
||||
type ValidationError struct {
|
||||
Path string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e ValidationError) Error() string {
|
||||
return fmt.Sprintf("ValidationError(%s): %v", e.Path, e.Err)
|
||||
}
|
||||
|
||||
type InvalidTypeError struct {
|
||||
Path string
|
||||
Expected string
|
||||
Actual string
|
||||
}
|
||||
|
||||
func (e InvalidTypeError) Error() string {
|
||||
return fmt.Sprintf("invalid type for %s: got %q, expected %q", e.Path, e.Actual, e.Expected)
|
||||
}
|
||||
|
||||
type MissingRequiredFieldError struct {
|
||||
Path string
|
||||
Field string
|
||||
}
|
||||
|
||||
func (e MissingRequiredFieldError) Error() string {
|
||||
return fmt.Sprintf("missing required field %q in %s", e.Field, e.Path)
|
||||
}
|
||||
|
||||
type UnknownFieldError struct {
|
||||
Path string
|
||||
Field string
|
||||
}
|
||||
|
||||
func (e UnknownFieldError) Error() string {
|
||||
return fmt.Sprintf("unknown field %q in %s", e.Field, e.Path)
|
||||
}
|
||||
|
||||
type InvalidObjectTypeError struct {
|
||||
Path string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (e InvalidObjectTypeError) Error() string {
|
||||
return fmt.Sprintf("unknown object type %q in %s", e.Type, e.Path)
|
||||
}
|
298
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/types.go
generated
vendored
298
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/types.go
generated
vendored
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
)
|
||||
|
||||
type validationItem interface {
|
||||
proto.SchemaVisitor
|
||||
|
||||
Errors() []error
|
||||
Path() *proto.Path
|
||||
}
|
||||
|
||||
type baseItem struct {
|
||||
errors errors
|
||||
path proto.Path
|
||||
}
|
||||
|
||||
// Errors returns the list of errors found for this item.
|
||||
func (item *baseItem) Errors() []error {
|
||||
return item.errors.Errors()
|
||||
}
|
||||
|
||||
// AddValidationError wraps the given error into a ValidationError and
|
||||
// attaches it to this item.
|
||||
func (item *baseItem) AddValidationError(err error) {
|
||||
item.errors.AppendErrors(ValidationError{Path: item.path.String(), Err: err})
|
||||
}
|
||||
|
||||
// AddError adds a regular (non-validation related) error to the list.
|
||||
func (item *baseItem) AddError(err error) {
|
||||
item.errors.AppendErrors(err)
|
||||
}
|
||||
|
||||
// CopyErrors adds a list of errors to this item. This is useful to copy
|
||||
// errors from subitems.
|
||||
func (item *baseItem) CopyErrors(errs []error) {
|
||||
item.errors.AppendErrors(errs...)
|
||||
}
|
||||
|
||||
// Path returns the path of this item, helps print useful errors.
|
||||
func (item *baseItem) Path() *proto.Path {
|
||||
return &item.path
|
||||
}
|
||||
|
||||
// mapItem represents a map entry in the yaml.
|
||||
type mapItem struct {
|
||||
baseItem
|
||||
|
||||
Map map[string]interface{}
|
||||
}
|
||||
|
||||
func (item *mapItem) sortedKeys() []string {
|
||||
sortedKeys := []string{}
|
||||
for key := range item.Map {
|
||||
sortedKeys = append(sortedKeys, key)
|
||||
}
|
||||
sort.Strings(sortedKeys)
|
||||
return sortedKeys
|
||||
}
|
||||
|
||||
var _ validationItem = &mapItem{}
|
||||
|
||||
func (item *mapItem) VisitPrimitive(schema *proto.Primitive) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: "map"})
|
||||
}
|
||||
|
||||
func (item *mapItem) VisitArray(schema *proto.Array) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "array", Actual: "map"})
|
||||
}
|
||||
|
||||
func (item *mapItem) VisitMap(schema *proto.Map) {
|
||||
for _, key := range item.sortedKeys() {
|
||||
subItem, err := itemFactory(item.Path().FieldPath(key), item.Map[key])
|
||||
if err != nil {
|
||||
item.AddError(err)
|
||||
continue
|
||||
}
|
||||
schema.SubType.Accept(subItem)
|
||||
item.CopyErrors(subItem.Errors())
|
||||
}
|
||||
}
|
||||
|
||||
func (item *mapItem) VisitKind(schema *proto.Kind) {
|
||||
// Verify each sub-field.
|
||||
for _, key := range item.sortedKeys() {
|
||||
if item.Map[key] == nil {
|
||||
continue
|
||||
}
|
||||
subItem, err := itemFactory(item.Path().FieldPath(key), item.Map[key])
|
||||
if err != nil {
|
||||
item.AddError(err)
|
||||
continue
|
||||
}
|
||||
if _, ok := schema.Fields[key]; !ok {
|
||||
item.AddValidationError(UnknownFieldError{Path: schema.GetPath().String(), Field: key})
|
||||
continue
|
||||
}
|
||||
schema.Fields[key].Accept(subItem)
|
||||
item.CopyErrors(subItem.Errors())
|
||||
}
|
||||
|
||||
// Verify that all required fields are present.
|
||||
for _, required := range schema.RequiredFields {
|
||||
if v, ok := item.Map[required]; !ok || v == nil {
|
||||
item.AddValidationError(MissingRequiredFieldError{Path: schema.GetPath().String(), Field: required})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (item *mapItem) VisitArbitrary(schema *proto.Arbitrary) {
|
||||
}
|
||||
|
||||
func (item *mapItem) VisitReference(schema proto.Reference) {
|
||||
// passthrough
|
||||
schema.SubSchema().Accept(item)
|
||||
}
|
||||
|
||||
// arrayItem represents a yaml array.
|
||||
type arrayItem struct {
|
||||
baseItem
|
||||
|
||||
Array []interface{}
|
||||
}
|
||||
|
||||
var _ validationItem = &arrayItem{}
|
||||
|
||||
func (item *arrayItem) VisitPrimitive(schema *proto.Primitive) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: "array"})
|
||||
}
|
||||
|
||||
func (item *arrayItem) VisitArray(schema *proto.Array) {
|
||||
for i, v := range item.Array {
|
||||
path := item.Path().ArrayPath(i)
|
||||
if v == nil {
|
||||
item.AddValidationError(InvalidObjectTypeError{Type: "nil", Path: path.String()})
|
||||
continue
|
||||
}
|
||||
subItem, err := itemFactory(path, v)
|
||||
if err != nil {
|
||||
item.AddError(err)
|
||||
continue
|
||||
}
|
||||
schema.SubType.Accept(subItem)
|
||||
item.CopyErrors(subItem.Errors())
|
||||
}
|
||||
}
|
||||
|
||||
func (item *arrayItem) VisitMap(schema *proto.Map) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: "array"})
|
||||
}
|
||||
|
||||
func (item *arrayItem) VisitKind(schema *proto.Kind) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: "array"})
|
||||
}
|
||||
|
||||
func (item *arrayItem) VisitArbitrary(schema *proto.Arbitrary) {
|
||||
}
|
||||
|
||||
func (item *arrayItem) VisitReference(schema proto.Reference) {
|
||||
// passthrough
|
||||
schema.SubSchema().Accept(item)
|
||||
}
|
||||
|
||||
// primitiveItem represents a yaml value.
|
||||
type primitiveItem struct {
|
||||
baseItem
|
||||
|
||||
Value interface{}
|
||||
Kind string
|
||||
}
|
||||
|
||||
var _ validationItem = &primitiveItem{}
|
||||
|
||||
func (item *primitiveItem) VisitPrimitive(schema *proto.Primitive) {
|
||||
// Some types of primitives can match more than one (a number
|
||||
// can be a string, but not the other way around). Return from
|
||||
// the switch if we have a valid possible type conversion
|
||||
// NOTE(apelisse): This logic is blindly copied from the
|
||||
// existing swagger logic, and I'm not sure I agree with it.
|
||||
switch schema.Type {
|
||||
case proto.Boolean:
|
||||
switch item.Kind {
|
||||
case proto.Boolean:
|
||||
return
|
||||
}
|
||||
case proto.Integer:
|
||||
switch item.Kind {
|
||||
case proto.Integer, proto.Number:
|
||||
return
|
||||
}
|
||||
case proto.Number:
|
||||
switch item.Kind {
|
||||
case proto.Number:
|
||||
return
|
||||
}
|
||||
case proto.String:
|
||||
return
|
||||
}
|
||||
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: item.Kind})
|
||||
}
|
||||
|
||||
func (item *primitiveItem) VisitArray(schema *proto.Array) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "array", Actual: item.Kind})
|
||||
}
|
||||
|
||||
func (item *primitiveItem) VisitMap(schema *proto.Map) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: item.Kind})
|
||||
}
|
||||
|
||||
func (item *primitiveItem) VisitKind(schema *proto.Kind) {
|
||||
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: item.Kind})
|
||||
}
|
||||
|
||||
func (item *primitiveItem) VisitArbitrary(schema *proto.Arbitrary) {
|
||||
}
|
||||
|
||||
func (item *primitiveItem) VisitReference(schema proto.Reference) {
|
||||
// passthrough
|
||||
schema.SubSchema().Accept(item)
|
||||
}
|
||||
|
||||
// itemFactory creates the relevant item type/visitor based on the current yaml type.
|
||||
func itemFactory(path proto.Path, v interface{}) (validationItem, error) {
|
||||
// We need to special case for no-type fields in yaml (e.g. empty item in list)
|
||||
if v == nil {
|
||||
return nil, InvalidObjectTypeError{Type: "nil", Path: path.String()}
|
||||
}
|
||||
kind := reflect.TypeOf(v).Kind()
|
||||
switch kind {
|
||||
case reflect.Bool:
|
||||
return &primitiveItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Value: v,
|
||||
Kind: proto.Boolean,
|
||||
}, nil
|
||||
case reflect.Int,
|
||||
reflect.Int8,
|
||||
reflect.Int16,
|
||||
reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint,
|
||||
reflect.Uint8,
|
||||
reflect.Uint16,
|
||||
reflect.Uint32,
|
||||
reflect.Uint64:
|
||||
return &primitiveItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Value: v,
|
||||
Kind: proto.Integer,
|
||||
}, nil
|
||||
case reflect.Float32,
|
||||
reflect.Float64:
|
||||
return &primitiveItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Value: v,
|
||||
Kind: proto.Number,
|
||||
}, nil
|
||||
case reflect.String:
|
||||
return &primitiveItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Value: v,
|
||||
Kind: proto.String,
|
||||
}, nil
|
||||
case reflect.Array,
|
||||
reflect.Slice:
|
||||
return &arrayItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Array: v.([]interface{}),
|
||||
}, nil
|
||||
case reflect.Map:
|
||||
return &mapItem{
|
||||
baseItem: baseItem{path: path},
|
||||
Map: v.(map[string]interface{}),
|
||||
}, nil
|
||||
}
|
||||
return nil, InvalidObjectTypeError{Type: kind.String(), Path: path.String()}
|
||||
}
|
30
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation.go
generated
vendored
30
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
)
|
||||
|
||||
func ValidateModel(obj interface{}, schema proto.Schema, name string) []error {
|
||||
rootValidation, err := itemFactory(proto.NewPath(name), obj)
|
||||
if err != nil {
|
||||
return []error{err}
|
||||
}
|
||||
schema.Accept(rootValidation)
|
||||
return rootValidation.Errors()
|
||||
}
|
49
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation_suite_test.go
generated
vendored
49
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation_suite_test.go
generated
vendored
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
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 validation
|
||||
|
||||
import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/ginkgo/config"
|
||||
. "github.com/onsi/ginkgo/types"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOpenapi(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecsWithDefaultAndCustomReporters(t, "Openapi Suite", []Reporter{newlineReporter{}})
|
||||
}
|
||||
|
||||
// Print a newline after the default newlineReporter due to issue
|
||||
// https://github.com/jstemmer/go-junit-report/issues/31
|
||||
type newlineReporter struct{}
|
||||
|
||||
func (newlineReporter) SpecSuiteWillBegin(config GinkgoConfigType, summary *SuiteSummary) {}
|
||||
|
||||
func (newlineReporter) BeforeSuiteDidRun(setupSummary *SetupSummary) {}
|
||||
|
||||
func (newlineReporter) AfterSuiteDidRun(setupSummary *SetupSummary) {}
|
||||
|
||||
func (newlineReporter) SpecWillRun(specSummary *SpecSummary) {}
|
||||
|
||||
func (newlineReporter) SpecDidComplete(specSummary *SpecSummary) {}
|
||||
|
||||
// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:"
|
||||
func (newlineReporter) SpecSuiteDidEnd(summary *SuiteSummary) { fmt.Printf("\n") }
|
369
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation_test.go
generated
vendored
369
vendor/k8s.io/kube-openapi/pkg/util/proto/validation/validation_test.go
generated
vendored
@@ -1,369 +0,0 @@
|
||||
/*
|
||||
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 validation_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/util/proto"
|
||||
"k8s.io/kube-openapi/pkg/util/proto/testing"
|
||||
"k8s.io/kube-openapi/pkg/util/proto/validation"
|
||||
)
|
||||
|
||||
var fakeSchema = testing.Fake{Path: filepath.Join("..", "testdata", "swagger.json")}
|
||||
|
||||
func Validate(models proto.Models, model string, data string) []error {
|
||||
var obj interface{}
|
||||
if err := yaml.Unmarshal([]byte(data), &obj); err != nil {
|
||||
return []error{fmt.Errorf("pre-validation: failed to parse yaml: %v", err)}
|
||||
}
|
||||
schema := models.LookupModel(model)
|
||||
if schema == nil {
|
||||
return []error{fmt.Errorf("pre-validation: couldn't find model %s", model)}
|
||||
}
|
||||
|
||||
return validation.ValidateModel(obj, schema, model)
|
||||
}
|
||||
|
||||
var _ = Describe("resource validation using OpenAPI Schema", func() {
|
||||
var models proto.Models
|
||||
BeforeEach(func() {
|
||||
s, err := fakeSchema.OpenAPISchema()
|
||||
Expect(err).To(BeNil())
|
||||
models, err = proto.NewOpenAPIData(s)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("finds Deployment in Schema and validates it", func() {
|
||||
err := Validate(models, "io.k8s.api.apps.v1beta1.Deployment", `
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: redis
|
||||
spec:
|
||||
containers:
|
||||
- image: redis
|
||||
name: redis
|
||||
`)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("validates a valid pod", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- args:
|
||||
- this
|
||||
- is
|
||||
- an
|
||||
- ok
|
||||
- command
|
||||
image: gcr.io/fake_project/fake_image:fake_tag
|
||||
name: master
|
||||
`)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("finds invalid command (string instead of []string) in Json Pod", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "name",
|
||||
"labels": {
|
||||
"name": "redis-master"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"name": "master",
|
||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
||||
"args": "this is a bad command"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
Expect(err).To(Equal([]error{
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args",
|
||||
Err: validation.InvalidTypeError{
|
||||
Path: "io.k8s.api.core.v1.Container.args",
|
||||
Expected: "array",
|
||||
Actual: "string",
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
It("fails because hostPort is string instead of int", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "apache-php",
|
||||
"labels": {
|
||||
"name": "apache-php"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [{
|
||||
"name": "shared-disk"
|
||||
}],
|
||||
"containers": [
|
||||
{
|
||||
"name": "apache-php",
|
||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
||||
"ports": [
|
||||
{
|
||||
"name": "apache",
|
||||
"hostPort": "13380",
|
||||
"containerPort": 80,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "shared-disk",
|
||||
"mountPath": "/var/www/html"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
Expect(err).To(Equal([]error{
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].ports[0].hostPort",
|
||||
Err: validation.InvalidTypeError{
|
||||
Path: "io.k8s.api.core.v1.ContainerPort.hostPort",
|
||||
Expected: "integer",
|
||||
Actual: "string",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
})
|
||||
|
||||
It("fails because volume is not an array of object", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
{
|
||||
"kind": "Pod",
|
||||
"apiVersion": "v1",
|
||||
"metadata": {
|
||||
"name": "apache-php",
|
||||
"labels": {
|
||||
"name": "apache-php"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"volumes": [
|
||||
"name": "shared-disk"
|
||||
],
|
||||
"containers": [
|
||||
{
|
||||
"name": "apache-php",
|
||||
"image": "gcr.io/fake_project/fake_image:fake_tag",
|
||||
"ports": [
|
||||
{
|
||||
"name": "apache",
|
||||
"hostPort": 13380,
|
||||
"containerPort": 80,
|
||||
"protocol": "TCP"
|
||||
}
|
||||
],
|
||||
"volumeMounts": [
|
||||
{
|
||||
"name": "shared-disk",
|
||||
"mountPath": "/var/www/html"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("fails because some string lists have empty strings", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- image: gcr.io/fake_project/fake_image:fake_tag
|
||||
name: master
|
||||
args:
|
||||
-
|
||||
command:
|
||||
-
|
||||
`)
|
||||
|
||||
Expect(err).To(Equal([]error{
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args",
|
||||
Err: validation.InvalidObjectTypeError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args[0]",
|
||||
Type: "nil",
|
||||
},
|
||||
},
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].command",
|
||||
Err: validation.InvalidObjectTypeError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].command[0]",
|
||||
Type: "nil",
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
It("fails if required fields are missing", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- command: ["my", "command"]
|
||||
`)
|
||||
|
||||
Expect(err).To(Equal([]error{
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
|
||||
Err: validation.MissingRequiredFieldError{
|
||||
Path: "io.k8s.api.core.v1.Container",
|
||||
Field: "name",
|
||||
},
|
||||
},
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
|
||||
Err: validation.MissingRequiredFieldError{
|
||||
Path: "io.k8s.api.core.v1.Container",
|
||||
Field: "image",
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
It("fails if required fields are empty", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- image:
|
||||
name:
|
||||
`)
|
||||
|
||||
Expect(err).To(Equal([]error{
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
|
||||
Err: validation.MissingRequiredFieldError{
|
||||
Path: "io.k8s.api.core.v1.Container",
|
||||
Field: "name",
|
||||
},
|
||||
},
|
||||
validation.ValidationError{
|
||||
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
|
||||
Err: validation.MissingRequiredFieldError{
|
||||
Path: "io.k8s.api.core.v1.Container",
|
||||
Field: "image",
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
||||
It("is fine with empty non-mandatory fields", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
labels:
|
||||
name: redis-master
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- image: image
|
||||
name: name
|
||||
command:
|
||||
`)
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("fails because apiVersion is not provided", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- name: name
|
||||
image: image
|
||||
`)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
It("fails because apiVersion type is not string and kind is not provided", func() {
|
||||
err := Validate(models, "io.k8s.api.core.v1.Pod", `
|
||||
apiVersion: 1
|
||||
metadata:
|
||||
name: name
|
||||
spec:
|
||||
containers:
|
||||
- name: name
|
||||
image: image
|
||||
`)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
})
|
27
vendor/k8s.io/kube-openapi/pkg/util/sets/empty.go
generated
vendored
27
vendor/k8s.io/kube-openapi/pkg/util/sets/empty.go
generated
vendored
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/empty.go
|
||||
// because in Kubernetes we don't allowed vendor code to import staging code. See
|
||||
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
|
||||
|
||||
package sets
|
||||
|
||||
// Empty is public since it is used by some internal API objects for conversions between external
|
||||
// string arrays and internal sets, and conversion logic requires public types today.
|
||||
type Empty struct{}
|
207
vendor/k8s.io/kube-openapi/pkg/util/sets/string.go
generated
vendored
207
vendor/k8s.io/kube-openapi/pkg/util/sets/string.go
generated
vendored
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by set-gen. DO NOT EDIT.
|
||||
|
||||
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/string.go
|
||||
// because in Kubernetes we don't allowed vendor code to import staging code. See
|
||||
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
|
||||
|
||||
package sets
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
|
||||
type String map[string]Empty
|
||||
|
||||
// NewString creates a String from a list of values.
|
||||
func NewString(items ...string) String {
|
||||
ss := String{}
|
||||
ss.Insert(items...)
|
||||
return ss
|
||||
}
|
||||
|
||||
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
|
||||
// If the value passed in is not actually a map, this will panic.
|
||||
func StringKeySet(theMap interface{}) String {
|
||||
v := reflect.ValueOf(theMap)
|
||||
ret := String{}
|
||||
|
||||
for _, keyValue := range v.MapKeys() {
|
||||
ret.Insert(keyValue.Interface().(string))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Insert adds items to the set.
|
||||
func (s String) Insert(items ...string) {
|
||||
for _, item := range items {
|
||||
s[item] = Empty{}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete removes all items from the set.
|
||||
func (s String) Delete(items ...string) {
|
||||
for _, item := range items {
|
||||
delete(s, item)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns true if and only if item is contained in the set.
|
||||
func (s String) Has(item string) bool {
|
||||
_, contained := s[item]
|
||||
return contained
|
||||
}
|
||||
|
||||
// HasAll returns true if and only if all items are contained in the set.
|
||||
func (s String) HasAll(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if !s.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// HasAny returns true if any items are contained in the set.
|
||||
func (s String) HasAny(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if s.Has(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Difference returns a set of objects that are not in s2
|
||||
// For example:
|
||||
// s1 = {a1, a2, a3}
|
||||
// s2 = {a1, a2, a4, a5}
|
||||
// s1.Difference(s2) = {a3}
|
||||
// s2.Difference(s1) = {a4, a5}
|
||||
func (s String) Difference(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s {
|
||||
if !s2.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Union returns a new set which includes items in either s1 or s2.
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a3, a4}
|
||||
// s1.Union(s2) = {a1, a2, a3, a4}
|
||||
// s2.Union(s1) = {a1, a2, a3, a4}
|
||||
func (s1 String) Union(s2 String) String {
|
||||
result := NewString()
|
||||
for key := range s1 {
|
||||
result.Insert(key)
|
||||
}
|
||||
for key := range s2 {
|
||||
result.Insert(key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection returns a new set which includes the item in BOTH s1 and s2
|
||||
// For example:
|
||||
// s1 = {a1, a2}
|
||||
// s2 = {a2, a3}
|
||||
// s1.Intersection(s2) = {a2}
|
||||
func (s1 String) Intersection(s2 String) String {
|
||||
var walk, other String
|
||||
result := NewString()
|
||||
if s1.Len() < s2.Len() {
|
||||
walk = s1
|
||||
other = s2
|
||||
} else {
|
||||
walk = s2
|
||||
other = s1
|
||||
}
|
||||
for key := range walk {
|
||||
if other.Has(key) {
|
||||
result.Insert(key)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// IsSuperset returns true if and only if s1 is a superset of s2.
|
||||
func (s1 String) IsSuperset(s2 String) bool {
|
||||
for item := range s2 {
|
||||
if !s1.Has(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal returns true if and only if s1 is equal (as a set) to s2.
|
||||
// Two sets are equal if their membership is identical.
|
||||
// (In practice, this means same elements, order doesn't matter)
|
||||
func (s1 String) Equal(s2 String) bool {
|
||||
return len(s1) == len(s2) && s1.IsSuperset(s2)
|
||||
}
|
||||
|
||||
type sortableSliceOfString []string
|
||||
|
||||
func (s sortableSliceOfString) Len() int { return len(s) }
|
||||
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
|
||||
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// List returns the contents as a sorted string slice.
|
||||
func (s String) List() []string {
|
||||
res := make(sortableSliceOfString, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
sort.Sort(res)
|
||||
return []string(res)
|
||||
}
|
||||
|
||||
// UnsortedList returns the slice with contents in random order.
|
||||
func (s String) UnsortedList() []string {
|
||||
res := make([]string, 0, len(s))
|
||||
for key := range s {
|
||||
res = append(res, key)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Returns a single element from the set.
|
||||
func (s String) PopAny() (string, bool) {
|
||||
for key := range s {
|
||||
s.Delete(key)
|
||||
return key, true
|
||||
}
|
||||
var zeroValue string
|
||||
return zeroValue, false
|
||||
}
|
||||
|
||||
// Len returns the size of the set.
|
||||
func (s String) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func lessString(lhs, rhs string) bool {
|
||||
return lhs < rhs
|
||||
}
|
79
vendor/k8s.io/kube-openapi/pkg/util/trie.go
generated
vendored
79
vendor/k8s.io/kube-openapi/pkg/util/trie.go
generated
vendored
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
Copyright 2016 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 util
|
||||
|
||||
// A simple trie implementation with Add and HasPrefix methods only.
|
||||
type Trie struct {
|
||||
children map[byte]*Trie
|
||||
wordTail bool
|
||||
word string
|
||||
}
|
||||
|
||||
// NewTrie creates a Trie and add all strings in the provided list to it.
|
||||
func NewTrie(list []string) Trie {
|
||||
ret := Trie{
|
||||
children: make(map[byte]*Trie),
|
||||
wordTail: false,
|
||||
}
|
||||
for _, v := range list {
|
||||
ret.Add(v)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Add adds a word to this trie
|
||||
func (t *Trie) Add(v string) {
|
||||
root := t
|
||||
for _, b := range []byte(v) {
|
||||
child, exists := root.children[b]
|
||||
if !exists {
|
||||
child = &Trie{
|
||||
children: make(map[byte]*Trie),
|
||||
wordTail: false,
|
||||
}
|
||||
root.children[b] = child
|
||||
}
|
||||
root = child
|
||||
}
|
||||
root.wordTail = true
|
||||
root.word = v
|
||||
}
|
||||
|
||||
// HasPrefix returns true of v has any of the prefixes stored in this trie.
|
||||
func (t *Trie) HasPrefix(v string) bool {
|
||||
_, has := t.GetPrefix(v)
|
||||
return has
|
||||
}
|
||||
|
||||
// GetPrefix is like HasPrefix but return the prefix in case of match or empty string otherwise.
|
||||
func (t *Trie) GetPrefix(v string) (string, bool) {
|
||||
root := t
|
||||
if root.wordTail {
|
||||
return root.word, true
|
||||
}
|
||||
for _, b := range []byte(v) {
|
||||
child, exists := root.children[b]
|
||||
if !exists {
|
||||
return "", false
|
||||
}
|
||||
if child.wordTail {
|
||||
return child.word, true
|
||||
}
|
||||
root = child
|
||||
}
|
||||
return "", false
|
||||
}
|
59
vendor/k8s.io/kube-openapi/pkg/util/util.go
generated
vendored
59
vendor/k8s.io/kube-openapi/pkg/util/util.go
generated
vendored
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToCanonicalName converts Golang package/type name into canonical OpenAPI name.
|
||||
// Examples:
|
||||
// Input: k8s.io/api/core/v1.Pod
|
||||
// Output: io.k8s.api.core.v1.Pod
|
||||
//
|
||||
// Input: k8s.io/api/core/v1
|
||||
// Output: io.k8s.api.core.v1
|
||||
func ToCanonicalName(name string) string {
|
||||
nameParts := strings.Split(name, "/")
|
||||
// Reverse first part. e.g., io.k8s... instead of k8s.io...
|
||||
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
|
||||
parts := strings.Split(nameParts[0], ".")
|
||||
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
|
||||
parts[i], parts[j] = parts[j], parts[i]
|
||||
}
|
||||
nameParts[0] = strings.Join(parts, ".")
|
||||
}
|
||||
return strings.Join(nameParts, ".")
|
||||
}
|
||||
|
||||
// GetCanonicalTypeName will find the canonical type name of a sample object, removing
|
||||
// the "vendor" part of the path
|
||||
func GetCanonicalTypeName(model interface{}) string {
|
||||
t := reflect.TypeOf(model)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.PkgPath() == "" {
|
||||
return t.Name()
|
||||
}
|
||||
path := t.PkgPath()
|
||||
if strings.Contains(path, "/vendor/") {
|
||||
path = path[strings.Index(path, "/vendor/")+len("/vendor/"):]
|
||||
}
|
||||
return path + "." + t.Name()
|
||||
}
|
58
vendor/k8s.io/kube-openapi/pkg/util/util_test.go
generated
vendored
58
vendor/k8s.io/kube-openapi/pkg/util/util_test.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCanonicalName(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"k8s.io/api/core/v1.Pod", "io.k8s.api.core.v1.Pod"},
|
||||
{"k8s.io/api/networking/v1/NetworkPolicy", "io.k8s.api.networking.v1.NetworkPolicy"},
|
||||
{"k8s.io/api/apps/v1beta2.Scale", "io.k8s.api.apps.v1beta2.Scale"},
|
||||
{"servicecatalog.k8s.io/foo/bar/v1alpha1.Baz", "io.k8s.servicecatalog.foo.bar.v1alpha1.Baz"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if got := ToCanonicalName(test.input); got != test.expected {
|
||||
t.Errorf("ToCanonicalName(%q) = %v", test.input, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type TestType struct{}
|
||||
|
||||
func TestGetCanonicalTypeName(t *testing.T) {
|
||||
|
||||
var tests = []struct {
|
||||
input interface{}
|
||||
expected string
|
||||
}{
|
||||
{TestType{}, "k8s.io/kube-openapi/pkg/util.TestType"},
|
||||
{&TestType{}, "k8s.io/kube-openapi/pkg/util.TestType"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if got := GetCanonicalTypeName(test.input); got != test.expected {
|
||||
t.Errorf("GetCanonicalTypeName(%q) = %v", reflect.TypeOf(test.input), got)
|
||||
}
|
||||
}
|
||||
}
|
40
vendor/k8s.io/kube-openapi/test/integration/README.md
generated
vendored
40
vendor/k8s.io/kube-openapi/test/integration/README.md
generated
vendored
@@ -1,40 +0,0 @@
|
||||
# Kube OpenAPI Integration Tests
|
||||
|
||||
## Running the integration tests
|
||||
|
||||
Within the current directory:
|
||||
|
||||
```bash
|
||||
$ go test -v .
|
||||
```
|
||||
|
||||
## Generating the golden Swagger definition file and API rule violation report
|
||||
|
||||
First, run the generator to create `openapi_generated.go` file which specifies
|
||||
the `OpenAPIDefinition` for each type, and generate the golden API rule
|
||||
violation report file . Note that if you do not pass a report
|
||||
filename (`./testdata/golden.report` in the command below) to let the generator
|
||||
to print API rule violations to the file, the generator will return error to stderr
|
||||
on API rule violations.
|
||||
|
||||
```bash
|
||||
$ go run ../../cmd/openapi-gen/openapi-gen.go -i "./testdata/listtype,./testdata/dummytype" -o pkg -p generated -O openapi_generated -r ./testdata/golden.report
|
||||
```
|
||||
The generated file `pkg/generated/openapi_generated.go` should have been created.
|
||||
|
||||
Next, run the OpenAPI builder to create the Swagger file which includes
|
||||
the definitions. The output file named `golden.json` will be output in
|
||||
the current directory.
|
||||
|
||||
```bash
|
||||
$ go run builder/main.go testdata/golden.json
|
||||
```
|
||||
|
||||
After the golden spec is generated, please clean up the generated file
|
||||
`pkg/generated/openapi_generated.go` before you commit. It's an intermediate product that doesn't need to be updated in kube-openapi repository. The checked-in file is kept minimum to make sure that `test/integration/builder` compiles. Please run:
|
||||
|
||||
```base
|
||||
$ git checkout pkg/generated/openapi_generated.go
|
||||
```
|
||||
|
||||
to discard any local change.
|
116
vendor/k8s.io/kube-openapi/test/integration/builder/main.go
generated
vendored
116
vendor/k8s.io/kube-openapi/test/integration/builder/main.go
generated
vendored
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/go-openapi/spec"
|
||||
"k8s.io/kube-openapi/pkg/builder"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/test/integration/pkg/generated"
|
||||
)
|
||||
|
||||
// TODO: Change this to output the generated swagger to stdout.
|
||||
const defaultSwaggerFile = "generated.json"
|
||||
|
||||
func main() {
|
||||
// Get the name of the generated swagger file from the args
|
||||
// if it exists; otherwise use the default file name.
|
||||
swaggerFilename := defaultSwaggerFile
|
||||
if len(os.Args) > 1 {
|
||||
swaggerFilename = os.Args[1]
|
||||
}
|
||||
|
||||
// Generate the definition names from the map keys returned
|
||||
// from GetOpenAPIDefinitions. Anonymous function returning empty
|
||||
// Ref is not used.
|
||||
var defNames []string
|
||||
for name, _ := range generated.GetOpenAPIDefinitions(func(name string) spec.Ref {
|
||||
return spec.Ref{}
|
||||
}) {
|
||||
defNames = append(defNames, name)
|
||||
}
|
||||
|
||||
// Create a minimal builder config, then call the builder with the definition names.
|
||||
config := createOpenAPIBuilderConfig()
|
||||
config.GetDefinitions = generated.GetOpenAPIDefinitions
|
||||
// Build the Paths using a simple WebService for the final spec
|
||||
swagger, serr := builder.BuildOpenAPISpec(createWebServices(), config)
|
||||
if serr != nil {
|
||||
log.Fatalf("ERROR: %s", serr.Error())
|
||||
}
|
||||
// Generate the definitions for the passed type names to put in the final spec.
|
||||
// Note that in reality one should run BuildOpenAPISpec to build the entire spec. We
|
||||
// separate the steps of building Paths and building Definitions here, because we
|
||||
// only have a simple WebService which doesn't wire the definitions up.
|
||||
definitionSwagger, err := builder.BuildOpenAPIDefinitionsForResources(config, defNames...)
|
||||
if err != nil {
|
||||
log.Fatalf("ERROR: %s", err.Error())
|
||||
}
|
||||
// Copy the generated definitions into the final swagger.
|
||||
swagger.Definitions = definitionSwagger.Definitions
|
||||
|
||||
// Marshal the swagger spec into JSON, then write it out.
|
||||
specBytes, err := json.MarshalIndent(swagger, " ", " ")
|
||||
if err != nil {
|
||||
log.Fatalf("json marshal error: %s", err.Error())
|
||||
}
|
||||
err = ioutil.WriteFile(swaggerFilename, specBytes, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("stdout write error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOpenAPIBuilderConfig hard-codes some values in the API builder
|
||||
// config for testing.
|
||||
func createOpenAPIBuilderConfig() *common.Config {
|
||||
return &common.Config{
|
||||
ProtocolList: []string{"https"},
|
||||
IgnorePrefixes: []string{"/swaggerapi"},
|
||||
Info: &spec.Info{
|
||||
InfoProps: spec.InfoProps{
|
||||
Title: "Integration Test",
|
||||
Version: "1.0",
|
||||
},
|
||||
},
|
||||
ResponseDefinitions: map[string]spec.Response{
|
||||
"NotFound": spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: "Entity not found.",
|
||||
},
|
||||
},
|
||||
},
|
||||
CommonResponses: map[int]spec.Response{
|
||||
404: *spec.ResponseRef("#/responses/NotFound"),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// createWebServices hard-codes a simple WebService which only defines a GET path
|
||||
// for testing.
|
||||
func createWebServices() []*restful.WebService {
|
||||
w := new(restful.WebService)
|
||||
// Define a dummy GET /test endpoint
|
||||
w = w.Route(w.GET("test").
|
||||
To(func(*restful.Request, *restful.Response) {}))
|
||||
return []*restful.WebService{w}
|
||||
}
|
159
vendor/k8s.io/kube-openapi/test/integration/integration_suite_test.go
generated
vendored
159
vendor/k8s.io/kube-openapi/test/integration/integration_suite_test.go
generated
vendored
@@ -1,159 +0,0 @@
|
||||
/*
|
||||
Copyright 2018 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 integration
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
)
|
||||
|
||||
const (
|
||||
testdataDir = "./testdata"
|
||||
inputDir = testdataDir + "/listtype" + "," + testdataDir + "/dummytype"
|
||||
outputBase = "pkg"
|
||||
outputPackage = "generated"
|
||||
outputBaseFileName = "openapi_generated"
|
||||
generatedSwaggerFileName = "generated.json"
|
||||
generatedReportFileName = "generated.report"
|
||||
goldenSwaggerFileName = "golden.json"
|
||||
goldenReportFileName = "golden.report"
|
||||
timeoutSeconds = 5.0
|
||||
)
|
||||
|
||||
func TestGenerators(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Integration Test Suite")
|
||||
}
|
||||
|
||||
var _ = Describe("Open API Definitions Generation", func() {
|
||||
|
||||
var (
|
||||
workingDirectory string
|
||||
tempDir string
|
||||
terr error
|
||||
openAPIGenPath string
|
||||
)
|
||||
|
||||
testdataFile := func(filename string) string { return filepath.Join(testdataDir, filename) }
|
||||
generatedFile := func(filename string) string { return filepath.Join(tempDir, filename) }
|
||||
|
||||
BeforeSuite(func() {
|
||||
// Explicitly manage working directory
|
||||
abs, err := filepath.Abs("")
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
workingDirectory = abs
|
||||
|
||||
// Create a temporary directory for generated swagger files.
|
||||
tempDir, terr = ioutil.TempDir("./", "openapi")
|
||||
Expect(terr).ShouldNot(HaveOccurred())
|
||||
|
||||
// Build the OpenAPI code generator.
|
||||
By("building openapi-gen")
|
||||
binary_path, berr := gexec.Build("../../cmd/openapi-gen/openapi-gen.go")
|
||||
Expect(berr).ShouldNot(HaveOccurred())
|
||||
openAPIGenPath = binary_path
|
||||
|
||||
// Run the OpenAPI code generator, creating OpenAPIDefinition code
|
||||
// to be compiled into builder.
|
||||
By("processing go idl with openapi-gen")
|
||||
gr := generatedFile(generatedReportFileName)
|
||||
command := exec.Command(openAPIGenPath,
|
||||
"-i", inputDir,
|
||||
"-o", outputBase,
|
||||
"-p", outputPackage,
|
||||
"-O", outputBaseFileName,
|
||||
"-r", gr,
|
||||
)
|
||||
command.Dir = workingDirectory
|
||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(session, timeoutSeconds).Should(gexec.Exit(0))
|
||||
|
||||
By("writing swagger")
|
||||
// Create the OpenAPI swagger builder.
|
||||
binary_path, berr = gexec.Build("./builder/main.go")
|
||||
Expect(berr).ShouldNot(HaveOccurred())
|
||||
|
||||
// Execute the builder, generating an OpenAPI swagger file with definitions.
|
||||
gs := generatedFile(generatedSwaggerFileName)
|
||||
By("writing swagger to " + gs)
|
||||
command = exec.Command(binary_path, gs)
|
||||
command.Dir = workingDirectory
|
||||
session, err = gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(session, timeoutSeconds).Should(gexec.Exit(0))
|
||||
})
|
||||
|
||||
AfterSuite(func() {
|
||||
os.RemoveAll(tempDir)
|
||||
gexec.CleanupBuildArtifacts()
|
||||
})
|
||||
|
||||
Describe("openapi-gen --verify", func() {
|
||||
It("Verifies that the existing files are correct", func() {
|
||||
command := exec.Command(openAPIGenPath,
|
||||
"-i", inputDir,
|
||||
"-o", outputBase,
|
||||
"-p", outputPackage,
|
||||
"-O", outputBaseFileName,
|
||||
"-r", testdataFile(goldenReportFileName),
|
||||
"--verify-only",
|
||||
)
|
||||
command.Dir = workingDirectory
|
||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(session, timeoutSeconds).Should(gexec.Exit(0))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Validating OpenAPI Definition Generation", func() {
|
||||
It("Generated OpenAPI swagger definitions should match golden files", func() {
|
||||
// Diff the generated swagger against the golden swagger. Exit code should be zero.
|
||||
command := exec.Command(
|
||||
"diff",
|
||||
testdataFile(goldenSwaggerFileName),
|
||||
generatedFile(generatedSwaggerFileName),
|
||||
)
|
||||
command.Dir = workingDirectory
|
||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(session, timeoutSeconds).Should(gexec.Exit(0))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Validating API Rule Violation Reporting", func() {
|
||||
It("Generated API rule violations should match golden report files", func() {
|
||||
// Diff the generated report against the golden report. Exit code should be zero.
|
||||
command := exec.Command(
|
||||
"diff",
|
||||
testdataFile(goldenReportFileName),
|
||||
generatedFile(generatedReportFileName),
|
||||
)
|
||||
command.Dir = workingDirectory
|
||||
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
|
||||
Expect(err).ShouldNot(HaveOccurred())
|
||||
Eventually(session, timeoutSeconds).Should(gexec.Exit(0))
|
||||
})
|
||||
})
|
||||
})
|
278
vendor/k8s.io/kube-openapi/test/integration/pkg/generated/openapi_generated.go
generated
vendored
278
vendor/k8s.io/kube-openapi/test/integration/pkg/generated/openapi_generated.go
generated
vendored
@@ -1,278 +0,0 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 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.
|
||||
*/
|
||||
|
||||
// Code generated by openapi-gen.go. DO NOT EDIT.
|
||||
|
||||
// This file was autogenerated by openapi-gen. Do not edit it manually!
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
spec "github.com/go-openapi/spec"
|
||||
common "k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
|
||||
return map[string]common.OpenAPIDefinition{
|
||||
"./testdata/dummytype.Bar": schema__testdata_dummytype_Bar(ref),
|
||||
"./testdata/dummytype.Baz": schema__testdata_dummytype_Baz(ref),
|
||||
"./testdata/dummytype.Foo": schema__testdata_dummytype_Foo(ref),
|
||||
"./testdata/dummytype.Waldo": schema__testdata_dummytype_Waldo(ref),
|
||||
"./testdata/listtype.AtomicList": schema__testdata_listtype_AtomicList(ref),
|
||||
"./testdata/listtype.Item": schema__testdata_listtype_Item(ref),
|
||||
"./testdata/listtype.MapList": schema__testdata_listtype_MapList(ref),
|
||||
"./testdata/listtype.SetList": schema__testdata_listtype_SetList(ref),
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_dummytype_Bar(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"ViolationBehind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"Violation": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"ViolationBehind", "Violation"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_dummytype_Baz(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Violation": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"ViolationBehind": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"boolean"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Violation", "ViolationBehind"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_dummytype_Foo(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Second": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"First": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Second", "First"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_dummytype_Waldo(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"First": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"Second": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"First", "Second"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_listtype_AtomicList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Field": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "atomic",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Field"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_listtype_Item(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Protocol": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
"Port": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"a": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"b": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
"c": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"integer"},
|
||||
Format: "int32",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Protocol", "Port"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_listtype_MapList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Field": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-map-keys": "port",
|
||||
"x-kubernetes-list-type": "map",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: ref("./testdata/listtype.Item"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Field"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{
|
||||
"./testdata/listtype.Item"},
|
||||
}
|
||||
}
|
||||
|
||||
func schema__testdata_listtype_SetList(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Properties: map[string]spec.Schema{
|
||||
"Field": {
|
||||
VendorExtensible: spec.VendorExtensible{
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-list-type": "set",
|
||||
},
|
||||
},
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"Field"},
|
||||
},
|
||||
},
|
||||
Dependencies: []string{},
|
||||
}
|
||||
}
|
36
vendor/k8s.io/kube-openapi/test/integration/testdata/dummytype/alpha.go
generated
vendored
36
vendor/k8s.io/kube-openapi/test/integration/testdata/dummytype/alpha.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
// The package is intended for testing the openapi-gen API rule
|
||||
// checker. The API rule violations are in format of:
|
||||
//
|
||||
// `{rule-name},{package},{type},{(optional) field}`
|
||||
//
|
||||
// The checker should sort the violations before
|
||||
// reporting to a file or stderr.
|
||||
//
|
||||
// We have the dummytype package separately from the listtype
|
||||
// package to test the sorting behavior on package level, e.g.
|
||||
//
|
||||
// -i "./testdata/listtype,./testdata/dummytype"
|
||||
// -i "./testdata/dummytype,./testdata/listtype"
|
||||
//
|
||||
// The violations from dummytype should always come first in
|
||||
// report.
|
||||
|
||||
package dummytype
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Foo struct {
|
||||
Second string
|
||||
First int
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Bar struct {
|
||||
ViolationBehind bool
|
||||
Violation bool
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Baz struct {
|
||||
Violation bool
|
||||
ViolationBehind bool
|
||||
}
|
24
vendor/k8s.io/kube-openapi/test/integration/testdata/dummytype/beta.go
generated
vendored
24
vendor/k8s.io/kube-openapi/test/integration/testdata/dummytype/beta.go
generated
vendored
@@ -1,24 +0,0 @@
|
||||
// The package is intended for testing the openapi-gen API rule
|
||||
// checker. The API rule violations are in format of:
|
||||
//
|
||||
// `{rule-name},{package},{type},{(optional) field}`
|
||||
//
|
||||
// The checker should sort the violations before
|
||||
// reporting to a file or stderr.
|
||||
//
|
||||
// We have the dummytype package separately from the listtype
|
||||
// package to test the sorting behavior on package level, e.g.
|
||||
//
|
||||
// -i "./testdata/listtype,./testdata/dummytype"
|
||||
// -i "./testdata/dummytype,./testdata/listtype"
|
||||
//
|
||||
// The violations from dummytype should always come first in
|
||||
// report.
|
||||
|
||||
package dummytype
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Waldo struct {
|
||||
First int
|
||||
Second string
|
||||
}
|
157
vendor/k8s.io/kube-openapi/test/integration/testdata/golden.json
generated
vendored
157
vendor/k8s.io/kube-openapi/test/integration/testdata/golden.json
generated
vendored
@@ -1,157 +0,0 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"title": "Integration Test",
|
||||
"version": "1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/test": {
|
||||
"get": {
|
||||
"schemes": [
|
||||
"https"
|
||||
],
|
||||
"operationId": "func1",
|
||||
"responses": {
|
||||
"404": {
|
||||
"$ref": "#/responses/NotFound"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dummytype.Bar": {
|
||||
"required": [
|
||||
"ViolationBehind",
|
||||
"Violation"
|
||||
],
|
||||
"properties": {
|
||||
"Violation": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ViolationBehind": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dummytype.Baz": {
|
||||
"required": [
|
||||
"Violation",
|
||||
"ViolationBehind"
|
||||
],
|
||||
"properties": {
|
||||
"Violation": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ViolationBehind": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dummytype.Foo": {
|
||||
"required": [
|
||||
"Second",
|
||||
"First"
|
||||
],
|
||||
"properties": {
|
||||
"First": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"Second": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dummytype.Waldo": {
|
||||
"required": [
|
||||
"First",
|
||||
"Second"
|
||||
],
|
||||
"properties": {
|
||||
"First": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"Second": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"listtype.AtomicList": {
|
||||
"required": [
|
||||
"Field"
|
||||
],
|
||||
"properties": {
|
||||
"Field": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-kubernetes-list-type": "atomic"
|
||||
}
|
||||
}
|
||||
},
|
||||
"listtype.Item": {
|
||||
"required": [
|
||||
"Protocol",
|
||||
"Port"
|
||||
],
|
||||
"properties": {
|
||||
"Port": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"Protocol": {
|
||||
"type": "string"
|
||||
},
|
||||
"a": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"b": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"c": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"listtype.MapList": {
|
||||
"required": [
|
||||
"Field"
|
||||
],
|
||||
"properties": {
|
||||
"Field": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/listtype.Item"
|
||||
},
|
||||
"x-kubernetes-list-map-keys": "port",
|
||||
"x-kubernetes-list-type": "map"
|
||||
}
|
||||
}
|
||||
},
|
||||
"listtype.SetList": {
|
||||
"required": [
|
||||
"Field"
|
||||
],
|
||||
"properties": {
|
||||
"Field": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"x-kubernetes-list-type": "set"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"NotFound": {
|
||||
"description": "Entity not found."
|
||||
}
|
||||
}
|
||||
}
|
14
vendor/k8s.io/kube-openapi/test/integration/testdata/golden.report
generated
vendored
14
vendor/k8s.io/kube-openapi/test/integration/testdata/golden.report
generated
vendored
@@ -1,14 +0,0 @@
|
||||
API rule violation: names_match,./testdata/dummytype,Bar,Violation
|
||||
API rule violation: names_match,./testdata/dummytype,Bar,ViolationBehind
|
||||
API rule violation: names_match,./testdata/dummytype,Baz,Violation
|
||||
API rule violation: names_match,./testdata/dummytype,Baz,ViolationBehind
|
||||
API rule violation: names_match,./testdata/dummytype,Foo,First
|
||||
API rule violation: names_match,./testdata/dummytype,Foo,Second
|
||||
API rule violation: names_match,./testdata/dummytype,Waldo,First
|
||||
API rule violation: names_match,./testdata/dummytype,Waldo,Second
|
||||
API rule violation: names_match,./testdata/listtype,AtomicList,Field
|
||||
API rule violation: names_match,./testdata/listtype,Item,Port
|
||||
API rule violation: names_match,./testdata/listtype,Item,Protocol
|
||||
API rule violation: names_match,./testdata/listtype,MapList,Field
|
||||
API rule violation: names_match,./testdata/listtype,SetList,Field
|
||||
API rule violation: omitempty_match_case,./testdata/listtype,Item,C
|
7
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/atomic-list.go
generated
vendored
7
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/atomic-list.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package listtype
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type AtomicList struct {
|
||||
// +listType=atomic
|
||||
Field []string
|
||||
}
|
20
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/map-list.go
generated
vendored
20
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/map-list.go
generated
vendored
@@ -1,20 +0,0 @@
|
||||
package listtype
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type MapList struct {
|
||||
// +listType=map
|
||||
// +listMapKey=port
|
||||
Field []Item
|
||||
}
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type Item struct {
|
||||
Protocol string
|
||||
Port int
|
||||
// +optional
|
||||
A int `json:"a"`
|
||||
// +optional
|
||||
B int `json:"b,omitempty"`
|
||||
// +optional
|
||||
C int `json:"c,omitEmpty"`
|
||||
}
|
7
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/set-list.go
generated
vendored
7
vendor/k8s.io/kube-openapi/test/integration/testdata/listtype/set-list.go
generated
vendored
@@ -1,7 +0,0 @@
|
||||
package listtype
|
||||
|
||||
// +k8s:openapi-gen=true
|
||||
type SetList struct {
|
||||
// +listType=set
|
||||
Field []string
|
||||
}
|
Reference in New Issue
Block a user