service_basic.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. Copyright 2016 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. "strconv"
  17. "strings"
  18. "k8s.io/api/core/v1"
  19. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  20. "k8s.io/apimachinery/pkg/runtime"
  21. "k8s.io/apimachinery/pkg/util/intstr"
  22. "k8s.io/apimachinery/pkg/util/validation"
  23. "k8s.io/kubernetes/pkg/kubectl/generate"
  24. )
  25. type ServiceCommonGeneratorV1 struct {
  26. Name string
  27. TCP []string
  28. Type v1.ServiceType
  29. ClusterIP string
  30. NodePort int
  31. ExternalName string
  32. }
  33. type ServiceClusterIPGeneratorV1 struct {
  34. ServiceCommonGeneratorV1
  35. }
  36. type ServiceNodePortGeneratorV1 struct {
  37. ServiceCommonGeneratorV1
  38. }
  39. type ServiceLoadBalancerGeneratorV1 struct {
  40. ServiceCommonGeneratorV1
  41. }
  42. // TODO: is this really necessary?
  43. type ServiceExternalNameGeneratorV1 struct {
  44. ServiceCommonGeneratorV1
  45. }
  46. func (ServiceClusterIPGeneratorV1) ParamNames() []generate.GeneratorParam {
  47. return []generate.GeneratorParam{
  48. {Name: "name", Required: true},
  49. {Name: "tcp", Required: true},
  50. {Name: "clusterip", Required: false},
  51. }
  52. }
  53. func (ServiceNodePortGeneratorV1) ParamNames() []generate.GeneratorParam {
  54. return []generate.GeneratorParam{
  55. {Name: "name", Required: true},
  56. {Name: "tcp", Required: true},
  57. {Name: "nodeport", Required: true},
  58. }
  59. }
  60. func (ServiceLoadBalancerGeneratorV1) ParamNames() []generate.GeneratorParam {
  61. return []generate.GeneratorParam{
  62. {Name: "name", Required: true},
  63. {Name: "tcp", Required: true},
  64. }
  65. }
  66. func (ServiceExternalNameGeneratorV1) ParamNames() []generate.GeneratorParam {
  67. return []generate.GeneratorParam{
  68. {Name: "name", Required: true},
  69. {Name: "externalname", Required: true},
  70. }
  71. }
  72. func parsePorts(portString string) (int32, intstr.IntOrString, error) {
  73. portStringSlice := strings.Split(portString, ":")
  74. port, err := strconv.Atoi(portStringSlice[0])
  75. if err != nil {
  76. return 0, intstr.FromInt(0), err
  77. }
  78. if errs := validation.IsValidPortNum(port); len(errs) != 0 {
  79. return 0, intstr.FromInt(0), fmt.Errorf(strings.Join(errs, ","))
  80. }
  81. if len(portStringSlice) == 1 {
  82. return int32(port), intstr.FromInt(int(port)), nil
  83. }
  84. var targetPort intstr.IntOrString
  85. if portNum, err := strconv.Atoi(portStringSlice[1]); err != nil {
  86. if errs := validation.IsValidPortName(portStringSlice[1]); len(errs) != 0 {
  87. return 0, intstr.FromInt(0), fmt.Errorf(strings.Join(errs, ","))
  88. }
  89. targetPort = intstr.FromString(portStringSlice[1])
  90. } else {
  91. if errs := validation.IsValidPortNum(portNum); len(errs) != 0 {
  92. return 0, intstr.FromInt(0), fmt.Errorf(strings.Join(errs, ","))
  93. }
  94. targetPort = intstr.FromInt(portNum)
  95. }
  96. return int32(port), targetPort, nil
  97. }
  98. func (s ServiceCommonGeneratorV1) GenerateCommon(params map[string]interface{}) error {
  99. name, isString := params["name"].(string)
  100. if !isString {
  101. return fmt.Errorf("expected string, saw %v for 'name'", name)
  102. }
  103. tcpStrings, isArray := params["tcp"].([]string)
  104. if !isArray {
  105. return fmt.Errorf("expected []string, found :%v", tcpStrings)
  106. }
  107. clusterip, isString := params["clusterip"].(string)
  108. if !isString {
  109. return fmt.Errorf("expected string, saw %v for 'clusterip'", clusterip)
  110. }
  111. externalname, isString := params["externalname"].(string)
  112. if !isString {
  113. return fmt.Errorf("expected string, saw %v for 'externalname'", externalname)
  114. }
  115. s.Name = name
  116. s.TCP = tcpStrings
  117. s.ClusterIP = clusterip
  118. s.ExternalName = externalname
  119. return nil
  120. }
  121. func (s ServiceLoadBalancerGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
  122. err := generate.ValidateParams(s.ParamNames(), params)
  123. if err != nil {
  124. return nil, err
  125. }
  126. delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeLoadBalancer, ClusterIP: ""}
  127. err = delegate.GenerateCommon(params)
  128. if err != nil {
  129. return nil, err
  130. }
  131. return delegate.StructuredGenerate()
  132. }
  133. func (s ServiceNodePortGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
  134. err := generate.ValidateParams(s.ParamNames(), params)
  135. if err != nil {
  136. return nil, err
  137. }
  138. delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeNodePort, ClusterIP: ""}
  139. err = delegate.GenerateCommon(params)
  140. if err != nil {
  141. return nil, err
  142. }
  143. return delegate.StructuredGenerate()
  144. }
  145. func (s ServiceClusterIPGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
  146. err := generate.ValidateParams(s.ParamNames(), params)
  147. if err != nil {
  148. return nil, err
  149. }
  150. delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeClusterIP, ClusterIP: ""}
  151. err = delegate.GenerateCommon(params)
  152. if err != nil {
  153. return nil, err
  154. }
  155. return delegate.StructuredGenerate()
  156. }
  157. func (s ServiceExternalNameGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
  158. err := generate.ValidateParams(s.ParamNames(), params)
  159. if err != nil {
  160. return nil, err
  161. }
  162. delegate := &ServiceCommonGeneratorV1{Type: v1.ServiceTypeExternalName, ClusterIP: ""}
  163. err = delegate.GenerateCommon(params)
  164. if err != nil {
  165. return nil, err
  166. }
  167. return delegate.StructuredGenerate()
  168. }
  169. // validate validates required fields are set to support structured generation
  170. // TODO(xiangpengzhao): validate ports are identity mapped for headless service when we enforce that in validation.validateServicePort.
  171. func (s ServiceCommonGeneratorV1) validate() error {
  172. if len(s.Name) == 0 {
  173. return fmt.Errorf("name must be specified")
  174. }
  175. if len(s.Type) == 0 {
  176. return fmt.Errorf("type must be specified")
  177. }
  178. if s.ClusterIP == v1.ClusterIPNone && s.Type != v1.ServiceTypeClusterIP {
  179. return fmt.Errorf("ClusterIP=None can only be used with ClusterIP service type")
  180. }
  181. if s.ClusterIP != v1.ClusterIPNone && len(s.TCP) == 0 && s.Type != v1.ServiceTypeExternalName {
  182. return fmt.Errorf("at least one tcp port specifier must be provided")
  183. }
  184. if s.Type == v1.ServiceTypeExternalName {
  185. if errs := validation.IsDNS1123Subdomain(s.ExternalName); len(errs) != 0 {
  186. return fmt.Errorf("invalid service external name %s", s.ExternalName)
  187. }
  188. }
  189. return nil
  190. }
  191. func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) {
  192. err := s.validate()
  193. if err != nil {
  194. return nil, err
  195. }
  196. ports := []v1.ServicePort{}
  197. for _, tcpString := range s.TCP {
  198. port, targetPort, err := parsePorts(tcpString)
  199. if err != nil {
  200. return nil, err
  201. }
  202. portName := strings.Replace(tcpString, ":", "-", -1)
  203. ports = append(ports, v1.ServicePort{
  204. Name: portName,
  205. Port: port,
  206. TargetPort: targetPort,
  207. Protocol: v1.Protocol("TCP"),
  208. NodePort: int32(s.NodePort),
  209. })
  210. }
  211. // setup default label and selector
  212. labels := map[string]string{}
  213. labels["app"] = s.Name
  214. selector := map[string]string{}
  215. selector["app"] = s.Name
  216. service := v1.Service{
  217. ObjectMeta: metav1.ObjectMeta{
  218. Name: s.Name,
  219. Labels: labels,
  220. },
  221. Spec: v1.ServiceSpec{
  222. Type: v1.ServiceType(s.Type),
  223. Selector: selector,
  224. Ports: ports,
  225. ExternalName: s.ExternalName,
  226. },
  227. }
  228. if len(s.ClusterIP) > 0 {
  229. service.Spec.ClusterIP = s.ClusterIP
  230. }
  231. return &service, nil
  232. }