testapi.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package testapi provides a helper for retrieving the KUBE_TEST_API environment variable.
  14. //
  15. // TODO(lavalamp): this package is a huge disaster at the moment. I intend to
  16. // refactor. All code currently using this package should change:
  17. // 1. Declare your own api.Registry.APIGroupRegistrationManager in your own test code.
  18. // 2. Import the relevant install packages.
  19. // 3. Register the types you need, from the announced.APIGroupAnnouncementManager.
  20. package testapi
  21. import (
  22. "fmt"
  23. "mime"
  24. "os"
  25. "reflect"
  26. "strings"
  27. "k8s.io/apimachinery/pkg/runtime"
  28. "k8s.io/apimachinery/pkg/runtime/schema"
  29. "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
  30. "k8s.io/kubernetes/pkg/api/legacyscheme"
  31. "k8s.io/kubernetes/pkg/apis/admission"
  32. "k8s.io/kubernetes/pkg/apis/admissionregistration"
  33. "k8s.io/kubernetes/pkg/apis/apps"
  34. "k8s.io/kubernetes/pkg/apis/auditregistration"
  35. "k8s.io/kubernetes/pkg/apis/authorization"
  36. "k8s.io/kubernetes/pkg/apis/autoscaling"
  37. "k8s.io/kubernetes/pkg/apis/batch"
  38. "k8s.io/kubernetes/pkg/apis/certificates"
  39. "k8s.io/kubernetes/pkg/apis/coordination"
  40. api "k8s.io/kubernetes/pkg/apis/core"
  41. "k8s.io/kubernetes/pkg/apis/events"
  42. "k8s.io/kubernetes/pkg/apis/extensions"
  43. "k8s.io/kubernetes/pkg/apis/imagepolicy"
  44. "k8s.io/kubernetes/pkg/apis/networking"
  45. "k8s.io/kubernetes/pkg/apis/node"
  46. "k8s.io/kubernetes/pkg/apis/policy"
  47. "k8s.io/kubernetes/pkg/apis/rbac"
  48. "k8s.io/kubernetes/pkg/apis/scheduling"
  49. "k8s.io/kubernetes/pkg/apis/settings"
  50. "k8s.io/kubernetes/pkg/apis/storage"
  51. // Initialize install packages
  52. _ "k8s.io/kubernetes/pkg/apis/admission/install"
  53. _ "k8s.io/kubernetes/pkg/apis/admissionregistration/install"
  54. _ "k8s.io/kubernetes/pkg/apis/apps/install"
  55. _ "k8s.io/kubernetes/pkg/apis/auditregistration/install"
  56. _ "k8s.io/kubernetes/pkg/apis/authentication/install"
  57. _ "k8s.io/kubernetes/pkg/apis/authorization/install"
  58. _ "k8s.io/kubernetes/pkg/apis/autoscaling/install"
  59. _ "k8s.io/kubernetes/pkg/apis/batch/install"
  60. _ "k8s.io/kubernetes/pkg/apis/certificates/install"
  61. _ "k8s.io/kubernetes/pkg/apis/coordination/install"
  62. _ "k8s.io/kubernetes/pkg/apis/core/install"
  63. _ "k8s.io/kubernetes/pkg/apis/events/install"
  64. _ "k8s.io/kubernetes/pkg/apis/extensions/install"
  65. _ "k8s.io/kubernetes/pkg/apis/imagepolicy/install"
  66. _ "k8s.io/kubernetes/pkg/apis/networking/install"
  67. _ "k8s.io/kubernetes/pkg/apis/node/install"
  68. _ "k8s.io/kubernetes/pkg/apis/policy/install"
  69. _ "k8s.io/kubernetes/pkg/apis/rbac/install"
  70. _ "k8s.io/kubernetes/pkg/apis/scheduling/install"
  71. _ "k8s.io/kubernetes/pkg/apis/settings/install"
  72. _ "k8s.io/kubernetes/pkg/apis/storage/install"
  73. )
  74. // Variables to store GroupName
  75. var (
  76. Groups = make(map[string]TestGroup)
  77. Default TestGroup
  78. Autoscaling TestGroup
  79. Batch TestGroup
  80. Extensions TestGroup
  81. Apps TestGroup
  82. Policy TestGroup
  83. Rbac TestGroup
  84. Storage TestGroup
  85. Admission TestGroup
  86. serializer runtime.SerializerInfo
  87. storageSerializer runtime.SerializerInfo
  88. )
  89. // TestGroup contains GroupVersion to uniquely identify the API
  90. type TestGroup struct {
  91. externalGroupVersion schema.GroupVersion
  92. }
  93. func init() {
  94. if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 {
  95. var ok bool
  96. mediaType, _, err := mime.ParseMediaType(apiMediaType)
  97. if err != nil {
  98. panic(err)
  99. }
  100. serializer, ok = runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), mediaType)
  101. if !ok {
  102. panic(fmt.Sprintf("no serializer for %s", apiMediaType))
  103. }
  104. }
  105. if storageMediaType := StorageMediaType(); len(storageMediaType) > 0 {
  106. var ok bool
  107. mediaType, _, err := mime.ParseMediaType(storageMediaType)
  108. if err != nil {
  109. panic(err)
  110. }
  111. storageSerializer, ok = runtime.SerializerInfoForMediaType(legacyscheme.Codecs.SupportedMediaTypes(), mediaType)
  112. if !ok {
  113. panic(fmt.Sprintf("no serializer for %s", storageMediaType))
  114. }
  115. }
  116. kubeTestAPI := os.Getenv("KUBE_TEST_API")
  117. if len(kubeTestAPI) != 0 {
  118. // priority is "first in list preferred", so this has to run in reverse order
  119. testGroupVersions := strings.Split(kubeTestAPI, ",")
  120. for i := len(testGroupVersions) - 1; i >= 0; i-- {
  121. gvString := testGroupVersions[i]
  122. groupVersion, err := schema.ParseGroupVersion(gvString)
  123. if err != nil {
  124. panic(fmt.Sprintf("Error parsing groupversion %v: %v", gvString, err))
  125. }
  126. Groups[groupVersion.Group] = TestGroup{
  127. externalGroupVersion: groupVersion,
  128. }
  129. }
  130. }
  131. if _, ok := Groups[api.GroupName]; !ok {
  132. externalGroupVersion := schema.GroupVersion{Group: api.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(api.GroupName)[0].Version}
  133. Groups[api.GroupName] = TestGroup{
  134. externalGroupVersion: externalGroupVersion,
  135. }
  136. }
  137. if _, ok := Groups[extensions.GroupName]; !ok {
  138. externalGroupVersion := schema.GroupVersion{Group: extensions.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(extensions.GroupName)[0].Version}
  139. Groups[extensions.GroupName] = TestGroup{
  140. externalGroupVersion: externalGroupVersion,
  141. }
  142. }
  143. if _, ok := Groups[autoscaling.GroupName]; !ok {
  144. internalTypes := make(map[string]reflect.Type)
  145. for k, t := range legacyscheme.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
  146. if k == "Scale" {
  147. continue
  148. }
  149. internalTypes[k] = t
  150. }
  151. externalGroupVersion := schema.GroupVersion{Group: autoscaling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(autoscaling.GroupName)[0].Version}
  152. Groups[autoscaling.GroupName] = TestGroup{
  153. externalGroupVersion: externalGroupVersion,
  154. }
  155. }
  156. if _, ok := Groups[autoscaling.GroupName+"IntraGroup"]; !ok {
  157. internalTypes := make(map[string]reflect.Type)
  158. for k, t := range legacyscheme.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
  159. if k == "Scale" {
  160. internalTypes[k] = t
  161. break
  162. }
  163. }
  164. externalGroupVersion := schema.GroupVersion{Group: autoscaling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(autoscaling.GroupName)[0].Version}
  165. Groups[autoscaling.GroupName] = TestGroup{
  166. externalGroupVersion: externalGroupVersion,
  167. }
  168. }
  169. if _, ok := Groups[batch.GroupName]; !ok {
  170. externalGroupVersion := schema.GroupVersion{Group: batch.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(batch.GroupName)[0].Version}
  171. Groups[batch.GroupName] = TestGroup{
  172. externalGroupVersion: externalGroupVersion,
  173. }
  174. }
  175. if _, ok := Groups[apps.GroupName]; !ok {
  176. externalGroupVersion := schema.GroupVersion{Group: apps.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(apps.GroupName)[0].Version}
  177. Groups[apps.GroupName] = TestGroup{
  178. externalGroupVersion: externalGroupVersion,
  179. }
  180. }
  181. if _, ok := Groups[policy.GroupName]; !ok {
  182. externalGroupVersion := schema.GroupVersion{Group: policy.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(policy.GroupName)[0].Version}
  183. Groups[policy.GroupName] = TestGroup{
  184. externalGroupVersion: externalGroupVersion,
  185. }
  186. }
  187. if _, ok := Groups[rbac.GroupName]; !ok {
  188. externalGroupVersion := schema.GroupVersion{Group: rbac.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(rbac.GroupName)[0].Version}
  189. Groups[rbac.GroupName] = TestGroup{
  190. externalGroupVersion: externalGroupVersion,
  191. }
  192. }
  193. if _, ok := Groups[scheduling.GroupName]; !ok {
  194. externalGroupVersion := schema.GroupVersion{Group: scheduling.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(scheduling.GroupName)[0].Version}
  195. Groups[scheduling.GroupName] = TestGroup{
  196. externalGroupVersion: externalGroupVersion,
  197. }
  198. }
  199. if _, ok := Groups[settings.GroupName]; !ok {
  200. externalGroupVersion := schema.GroupVersion{Group: settings.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(settings.GroupName)[0].Version}
  201. Groups[settings.GroupName] = TestGroup{
  202. externalGroupVersion: externalGroupVersion,
  203. }
  204. }
  205. if _, ok := Groups[storage.GroupName]; !ok {
  206. externalGroupVersion := schema.GroupVersion{Group: storage.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(storage.GroupName)[0].Version}
  207. Groups[storage.GroupName] = TestGroup{
  208. externalGroupVersion: externalGroupVersion,
  209. }
  210. }
  211. if _, ok := Groups[certificates.GroupName]; !ok {
  212. externalGroupVersion := schema.GroupVersion{Group: certificates.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(certificates.GroupName)[0].Version}
  213. Groups[certificates.GroupName] = TestGroup{
  214. externalGroupVersion: externalGroupVersion,
  215. }
  216. }
  217. if _, ok := Groups[imagepolicy.GroupName]; !ok {
  218. externalGroupVersion := schema.GroupVersion{Group: imagepolicy.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(imagepolicy.GroupName)[0].Version}
  219. Groups[imagepolicy.GroupName] = TestGroup{
  220. externalGroupVersion: externalGroupVersion,
  221. }
  222. }
  223. if _, ok := Groups[authorization.GroupName]; !ok {
  224. externalGroupVersion := schema.GroupVersion{Group: authorization.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(authorization.GroupName)[0].Version}
  225. Groups[authorization.GroupName] = TestGroup{
  226. externalGroupVersion: externalGroupVersion,
  227. }
  228. }
  229. if _, ok := Groups[admissionregistration.GroupName]; !ok {
  230. externalGroupVersion := schema.GroupVersion{Group: admissionregistration.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(admissionregistration.GroupName)[0].Version}
  231. Groups[admissionregistration.GroupName] = TestGroup{
  232. externalGroupVersion: externalGroupVersion,
  233. }
  234. }
  235. if _, ok := Groups[admission.GroupName]; !ok {
  236. externalGroupVersion := schema.GroupVersion{Group: admission.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(admission.GroupName)[0].Version}
  237. Groups[admission.GroupName] = TestGroup{
  238. externalGroupVersion: externalGroupVersion,
  239. }
  240. }
  241. if _, ok := Groups[networking.GroupName]; !ok {
  242. externalGroupVersion := schema.GroupVersion{Group: networking.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(networking.GroupName)[0].Version}
  243. Groups[networking.GroupName] = TestGroup{
  244. externalGroupVersion: externalGroupVersion,
  245. }
  246. }
  247. if _, ok := Groups[node.GroupName]; !ok {
  248. externalGroupVersion := schema.GroupVersion{Group: node.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(node.GroupName)[0].Version}
  249. Groups[node.GroupName] = TestGroup{
  250. externalGroupVersion: externalGroupVersion,
  251. }
  252. }
  253. if _, ok := Groups[events.GroupName]; !ok {
  254. externalGroupVersion := schema.GroupVersion{Group: events.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(events.GroupName)[0].Version}
  255. Groups[events.GroupName] = TestGroup{
  256. externalGroupVersion: externalGroupVersion,
  257. }
  258. }
  259. if _, ok := Groups[coordination.GroupName]; !ok {
  260. externalGroupVersion := schema.GroupVersion{Group: coordination.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(coordination.GroupName)[0].Version}
  261. Groups[coordination.GroupName] = TestGroup{
  262. externalGroupVersion: externalGroupVersion,
  263. }
  264. }
  265. if _, ok := Groups[auditregistration.GroupName]; !ok {
  266. externalGroupVersion := schema.GroupVersion{Group: auditregistration.GroupName, Version: legacyscheme.Scheme.PrioritizedVersionsForGroup(auditregistration.GroupName)[0].Version}
  267. Groups[auditregistration.GroupName] = TestGroup{
  268. externalGroupVersion: externalGroupVersion,
  269. }
  270. }
  271. Default = Groups[api.GroupName]
  272. Autoscaling = Groups[autoscaling.GroupName]
  273. Batch = Groups[batch.GroupName]
  274. Apps = Groups[apps.GroupName]
  275. Policy = Groups[policy.GroupName]
  276. Extensions = Groups[extensions.GroupName]
  277. Rbac = Groups[rbac.GroupName]
  278. Storage = Groups[storage.GroupName]
  279. Admission = Groups[admission.GroupName]
  280. }
  281. // GroupVersion makes copy of schema.GroupVersion
  282. func (g TestGroup) GroupVersion() *schema.GroupVersion {
  283. copyOfGroupVersion := g.externalGroupVersion
  284. return &copyOfGroupVersion
  285. }
  286. // Codec returns the codec for the API version to test against, as set by the
  287. // KUBE_TEST_API_TYPE env var.
  288. func (g TestGroup) Codec() runtime.Codec {
  289. if serializer.Serializer == nil {
  290. return legacyscheme.Codecs.LegacyCodec(g.externalGroupVersion)
  291. }
  292. return legacyscheme.Codecs.CodecForVersions(serializer.Serializer, legacyscheme.Codecs.UniversalDeserializer(), schema.GroupVersions{g.externalGroupVersion}, nil)
  293. }
  294. // StorageMediaType finds media type set by KUBE_TEST_API_STORAGE_TYPE env var used to store objects in storage
  295. func StorageMediaType() string {
  296. return os.Getenv("KUBE_TEST_API_STORAGE_TYPE")
  297. }
  298. // StorageCodec returns the codec for the API version to store in etcd, as set by the
  299. // KUBE_TEST_API_STORAGE_TYPE env var.
  300. func (g TestGroup) StorageCodec() runtime.Codec {
  301. s := storageSerializer.Serializer
  302. if s == nil {
  303. return legacyscheme.Codecs.LegacyCodec(g.externalGroupVersion)
  304. }
  305. // etcd2 only supports string data - we must wrap any result before returning
  306. // TODO: remove for etcd3 / make parameterizable
  307. if !storageSerializer.EncodesAsText {
  308. s = runtime.NewBase64Serializer(s, s)
  309. }
  310. ds := recognizer.NewDecoder(s, legacyscheme.Codecs.UniversalDeserializer())
  311. return legacyscheme.Codecs.CodecForVersions(s, ds, schema.GroupVersions{g.externalGroupVersion}, nil)
  312. }
  313. // SelfLink returns a self link that will appear to be for the version Version().
  314. // 'resource' should be the resource path, e.g. "pods" for the Pod type. 'name' should be
  315. // empty for lists.
  316. func (g TestGroup) SelfLink(resource, name string) string {
  317. if g.externalGroupVersion.Group == api.GroupName {
  318. if name == "" {
  319. return fmt.Sprintf("/api/%s/%s", g.externalGroupVersion.Version, resource)
  320. }
  321. return fmt.Sprintf("/api/%s/%s/%s", g.externalGroupVersion.Version, resource, name)
  322. }
  323. // TODO: will need a /apis prefix once we have proper multi-group
  324. // support
  325. if name == "" {
  326. return fmt.Sprintf("/apis/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource)
  327. }
  328. return fmt.Sprintf("/apis/%s/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource, name)
  329. }
  330. // ResourcePathWithPrefix returns the appropriate path for the given prefix (watch, proxy, redirect, etc), resource, namespace and name.
  331. // For ex, this is of the form:
  332. // /api/v1/watch/namespaces/foo/pods/pod0 for v1.
  333. func (g TestGroup) ResourcePathWithPrefix(prefix, resource, namespace, name string) string {
  334. var path string
  335. if g.externalGroupVersion.Group == api.GroupName {
  336. path = "/api/" + g.externalGroupVersion.Version
  337. } else {
  338. // TODO: switch back once we have proper multiple group support
  339. // path = "/apis/" + g.Group + "/" + Version(group...)
  340. path = "/apis/" + g.externalGroupVersion.Group + "/" + g.externalGroupVersion.Version
  341. }
  342. if prefix != "" {
  343. path = path + "/" + prefix
  344. }
  345. if namespace != "" {
  346. path = path + "/namespaces/" + namespace
  347. }
  348. // Resource names are lower case.
  349. resource = strings.ToLower(resource)
  350. if resource != "" {
  351. path = path + "/" + resource
  352. }
  353. if name != "" {
  354. path = path + "/" + name
  355. }
  356. return path
  357. }
  358. // ResourcePath returns the appropriate path for the given resource, namespace and name.
  359. // For example, this is of the form:
  360. // /api/v1/namespaces/foo/pods/pod0 for v1.
  361. func (g TestGroup) ResourcePath(resource, namespace, name string) string {
  362. return g.ResourcePathWithPrefix("", resource, namespace, name)
  363. }
  364. // SubResourcePath returns the appropriate path for the given resource, namespace,
  365. // name and subresource.
  366. func (g TestGroup) SubResourcePath(resource, namespace, name, sub string) string {
  367. path := g.ResourcePathWithPrefix("", resource, namespace, name)
  368. if sub != "" {
  369. path = path + "/" + sub
  370. }
  371. return path
  372. }