generator.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. Copyright 2018 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 versioned
  14. import (
  15. "fmt"
  16. "io"
  17. appsv1 "k8s.io/api/apps/v1"
  18. appsv1beta1 "k8s.io/api/apps/v1beta1"
  19. batchv1 "k8s.io/api/batch/v1"
  20. batchv1beta1 "k8s.io/api/batch/v1beta1"
  21. batchv2alpha1 "k8s.io/api/batch/v2alpha1"
  22. extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
  23. apierrors "k8s.io/apimachinery/pkg/api/errors"
  24. "k8s.io/apimachinery/pkg/runtime/schema"
  25. "k8s.io/client-go/discovery"
  26. "k8s.io/kubernetes/pkg/kubectl/generate"
  27. )
  28. // GeneratorFn gives a way to easily override the function for unit testing if needed
  29. var GeneratorFn generate.GeneratorFunc = DefaultGenerators
  30. const (
  31. // TODO(sig-cli): Enforce consistent naming for generators here.
  32. // See discussion in https://github.com/kubernetes/kubernetes/issues/46237
  33. // before you add any more.
  34. RunV1GeneratorName = "run/v1"
  35. RunPodV1GeneratorName = "run-pod/v1"
  36. ServiceV1GeneratorName = "service/v1"
  37. ServiceV2GeneratorName = "service/v2"
  38. ServiceNodePortGeneratorV1Name = "service-nodeport/v1"
  39. ServiceClusterIPGeneratorV1Name = "service-clusterip/v1"
  40. ServiceLoadBalancerGeneratorV1Name = "service-loadbalancer/v1"
  41. ServiceExternalNameGeneratorV1Name = "service-externalname/v1"
  42. ServiceAccountV1GeneratorName = "serviceaccount/v1"
  43. HorizontalPodAutoscalerV1GeneratorName = "horizontalpodautoscaler/v1"
  44. DeploymentV1Beta1GeneratorName = "deployment/v1beta1"
  45. DeploymentAppsV1Beta1GeneratorName = "deployment/apps.v1beta1"
  46. DeploymentAppsV1GeneratorName = "deployment/apps.v1"
  47. DeploymentBasicV1Beta1GeneratorName = "deployment-basic/v1beta1"
  48. DeploymentBasicAppsV1Beta1GeneratorName = "deployment-basic/apps.v1beta1"
  49. DeploymentBasicAppsV1GeneratorName = "deployment-basic/apps.v1"
  50. JobV1GeneratorName = "job/v1"
  51. CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1"
  52. CronJobV1Beta1GeneratorName = "cronjob/v1beta1"
  53. NamespaceV1GeneratorName = "namespace/v1"
  54. ResourceQuotaV1GeneratorName = "resourcequotas/v1"
  55. SecretV1GeneratorName = "secret/v1"
  56. SecretForDockerRegistryV1GeneratorName = "secret-for-docker-registry/v1"
  57. SecretForTLSV1GeneratorName = "secret-for-tls/v1"
  58. ConfigMapV1GeneratorName = "configmap/v1"
  59. ClusterRoleBindingV1GeneratorName = "clusterrolebinding.rbac.authorization.k8s.io/v1alpha1"
  60. RoleBindingV1GeneratorName = "rolebinding.rbac.authorization.k8s.io/v1alpha1"
  61. PodDisruptionBudgetV1GeneratorName = "poddisruptionbudget/v1beta1"
  62. PodDisruptionBudgetV2GeneratorName = "poddisruptionbudget/v1beta1/v2"
  63. PriorityClassV1Alpha1GeneratorName = "priorityclass/v1alpha1"
  64. PriorityClassV1Beta1GeneratorName = "priorityclass/v1beta1"
  65. PriorityClassV1GeneratorName = "priorityclass/v1"
  66. )
  67. // DefaultGenerators returns the set of default generators for use in Factory instances
  68. func DefaultGenerators(cmdName string) map[string]generate.Generator {
  69. var generator map[string]generate.Generator
  70. switch cmdName {
  71. case "expose":
  72. generator = map[string]generate.Generator{
  73. ServiceV1GeneratorName: ServiceGeneratorV1{},
  74. ServiceV2GeneratorName: ServiceGeneratorV2{},
  75. }
  76. case "service-clusterip":
  77. generator = map[string]generate.Generator{
  78. ServiceClusterIPGeneratorV1Name: ServiceClusterIPGeneratorV1{},
  79. }
  80. case "service-nodeport":
  81. generator = map[string]generate.Generator{
  82. ServiceNodePortGeneratorV1Name: ServiceNodePortGeneratorV1{},
  83. }
  84. case "service-loadbalancer":
  85. generator = map[string]generate.Generator{
  86. ServiceLoadBalancerGeneratorV1Name: ServiceLoadBalancerGeneratorV1{},
  87. }
  88. case "deployment":
  89. // Create Deployment has only StructuredGenerators and no
  90. // param-based Generators.
  91. // The StructuredGenerators are as follows (as of 2018-03-16):
  92. // DeploymentBasicV1Beta1GeneratorName -> DeploymentBasicGeneratorV1
  93. // DeploymentBasicAppsV1Beta1GeneratorName -> DeploymentBasicAppsGeneratorV1Beta1
  94. // DeploymentBasicAppsV1GeneratorName -> DeploymentBasicAppsGeneratorV1
  95. generator = map[string]generate.Generator{}
  96. case "run":
  97. generator = map[string]generate.Generator{
  98. RunV1GeneratorName: BasicReplicationController{},
  99. RunPodV1GeneratorName: BasicPod{},
  100. DeploymentV1Beta1GeneratorName: DeploymentV1Beta1{},
  101. DeploymentAppsV1Beta1GeneratorName: DeploymentAppsV1Beta1{},
  102. DeploymentAppsV1GeneratorName: DeploymentAppsV1{},
  103. JobV1GeneratorName: JobV1{},
  104. CronJobV2Alpha1GeneratorName: CronJobV2Alpha1{},
  105. CronJobV1Beta1GeneratorName: CronJobV1Beta1{},
  106. }
  107. case "namespace":
  108. generator = map[string]generate.Generator{
  109. NamespaceV1GeneratorName: NamespaceGeneratorV1{},
  110. }
  111. case "quota":
  112. generator = map[string]generate.Generator{
  113. ResourceQuotaV1GeneratorName: ResourceQuotaGeneratorV1{},
  114. }
  115. case "secret":
  116. generator = map[string]generate.Generator{
  117. SecretV1GeneratorName: SecretGeneratorV1{},
  118. }
  119. case "secret-for-docker-registry":
  120. generator = map[string]generate.Generator{
  121. SecretForDockerRegistryV1GeneratorName: SecretForDockerRegistryGeneratorV1{},
  122. }
  123. case "secret-for-tls":
  124. generator = map[string]generate.Generator{
  125. SecretForTLSV1GeneratorName: SecretForTLSGeneratorV1{},
  126. }
  127. }
  128. return generator
  129. }
  130. // FallbackGeneratorNameIfNecessary returns the name of the old generator
  131. // if server does not support new generator. Otherwise, the
  132. // generator string is returned unchanged.
  133. //
  134. // If the generator name is changed, print a warning message to let the user
  135. // know.
  136. func FallbackGeneratorNameIfNecessary(
  137. generatorName string,
  138. discoveryClient discovery.DiscoveryInterface,
  139. cmdErr io.Writer,
  140. ) (string, error) {
  141. switch generatorName {
  142. case DeploymentAppsV1GeneratorName:
  143. hasResource, err := HasResource(discoveryClient, appsv1.SchemeGroupVersion.WithResource("deployments"))
  144. if err != nil {
  145. return "", err
  146. }
  147. if !hasResource {
  148. return FallbackGeneratorNameIfNecessary(DeploymentAppsV1Beta1GeneratorName, discoveryClient, cmdErr)
  149. }
  150. case DeploymentAppsV1Beta1GeneratorName:
  151. hasResource, err := HasResource(discoveryClient, appsv1beta1.SchemeGroupVersion.WithResource("deployments"))
  152. if err != nil {
  153. return "", err
  154. }
  155. if !hasResource {
  156. return FallbackGeneratorNameIfNecessary(DeploymentV1Beta1GeneratorName, discoveryClient, cmdErr)
  157. }
  158. case DeploymentV1Beta1GeneratorName:
  159. hasResource, err := HasResource(discoveryClient, extensionsv1beta1.SchemeGroupVersion.WithResource("deployments"))
  160. if err != nil {
  161. return "", err
  162. }
  163. if !hasResource {
  164. return RunV1GeneratorName, nil
  165. }
  166. case DeploymentBasicAppsV1GeneratorName:
  167. hasResource, err := HasResource(discoveryClient, appsv1.SchemeGroupVersion.WithResource("deployments"))
  168. if err != nil {
  169. return "", err
  170. }
  171. if !hasResource {
  172. return FallbackGeneratorNameIfNecessary(DeploymentBasicAppsV1Beta1GeneratorName, discoveryClient, cmdErr)
  173. }
  174. case DeploymentBasicAppsV1Beta1GeneratorName:
  175. hasResource, err := HasResource(discoveryClient, appsv1beta1.SchemeGroupVersion.WithResource("deployments"))
  176. if err != nil {
  177. return "", err
  178. }
  179. if !hasResource {
  180. return DeploymentBasicV1Beta1GeneratorName, nil
  181. }
  182. case JobV1GeneratorName:
  183. hasResource, err := HasResource(discoveryClient, batchv1.SchemeGroupVersion.WithResource("jobs"))
  184. if err != nil {
  185. return "", err
  186. }
  187. if !hasResource {
  188. return RunPodV1GeneratorName, nil
  189. }
  190. case CronJobV1Beta1GeneratorName:
  191. hasResource, err := HasResource(discoveryClient, batchv1beta1.SchemeGroupVersion.WithResource("cronjobs"))
  192. if err != nil {
  193. return "", err
  194. }
  195. if !hasResource {
  196. return FallbackGeneratorNameIfNecessary(CronJobV2Alpha1GeneratorName, discoveryClient, cmdErr)
  197. }
  198. case CronJobV2Alpha1GeneratorName:
  199. hasResource, err := HasResource(discoveryClient, batchv2alpha1.SchemeGroupVersion.WithResource("cronjobs"))
  200. if err != nil {
  201. return "", err
  202. }
  203. if !hasResource {
  204. return JobV1GeneratorName, nil
  205. }
  206. }
  207. return generatorName, nil
  208. }
  209. func HasResource(client discovery.DiscoveryInterface, resource schema.GroupVersionResource) (bool, error) {
  210. resources, err := client.ServerResourcesForGroupVersion(resource.GroupVersion().String())
  211. if apierrors.IsNotFound(err) {
  212. // entire group is missing
  213. return false, nil
  214. }
  215. if err != nil {
  216. // other errors error
  217. return false, fmt.Errorf("failed to discover supported resources: %v", err)
  218. }
  219. for _, serverResource := range resources.APIResources {
  220. if serverResource.Name == resource.Resource {
  221. return true, nil
  222. }
  223. }
  224. return false, nil
  225. }