1
16
17 package versioned
18
19 import (
20 "fmt"
21 "strconv"
22 "strings"
23
24 "k8s.io/api/core/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apimachinery/pkg/util/intstr"
28 "k8s.io/kubectl/pkg/generate"
29 )
30
31
32 type ServiceGeneratorV1 struct{}
33
34 func (ServiceGeneratorV1) ParamNames() []generate.GeneratorParam {
35 return paramNames()
36 }
37
38 func (ServiceGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
39 params["port-name"] = "default"
40 return generateService(params)
41 }
42
43 type ServiceGeneratorV2 struct{}
44
45 func (ServiceGeneratorV2) ParamNames() []generate.GeneratorParam {
46 return paramNames()
47 }
48
49 func (ServiceGeneratorV2) Generate(params map[string]interface{}) (runtime.Object, error) {
50 return generateService(params)
51 }
52
53 func paramNames() []generate.GeneratorParam {
54 return []generate.GeneratorParam{
55 {Name: "default-name", Required: true},
56 {Name: "name", Required: false},
57 {Name: "selector", Required: true},
58
59
60 {Name: "port", Required: false},
61
62
63 {Name: "ports", Required: false},
64 {Name: "labels", Required: false},
65 {Name: "external-ip", Required: false},
66 {Name: "load-balancer-ip", Required: false},
67 {Name: "type", Required: false},
68 {Name: "protocol", Required: false},
69
70
71 {Name: "protocols", Required: false},
72 {Name: "container-port", Required: false},
73 {Name: "target-port", Required: false},
74 {Name: "port-name", Required: false},
75 {Name: "session-affinity", Required: false},
76 {Name: "cluster-ip", Required: false},
77 }
78 }
79
80 func generateService(genericParams map[string]interface{}) (runtime.Object, error) {
81 params := map[string]string{}
82 for key, value := range genericParams {
83 strVal, isString := value.(string)
84 if !isString {
85 return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
86 }
87 params[key] = strVal
88 }
89 selectorString, found := params["selector"]
90 if !found || len(selectorString) == 0 {
91 return nil, fmt.Errorf("'selector' is a required parameter")
92 }
93 selector, err := generate.ParseLabels(selectorString)
94 if err != nil {
95 return nil, err
96 }
97
98 labelsString, found := params["labels"]
99 var labels map[string]string
100 if found && len(labelsString) > 0 {
101 labels, err = generate.ParseLabels(labelsString)
102 if err != nil {
103 return nil, err
104 }
105 }
106
107 name, found := params["name"]
108 if !found || len(name) == 0 {
109 name, found = params["default-name"]
110 if !found || len(name) == 0 {
111 return nil, fmt.Errorf("'name' is a required parameter")
112 }
113 }
114
115 isHeadlessService := params["cluster-ip"] == "None"
116
117 ports := []v1.ServicePort{}
118 servicePortName, found := params["port-name"]
119 if !found {
120
121 servicePortName = ""
122 }
123
124 protocolsString, found := params["protocols"]
125 var portProtocolMap map[string]string
126 if found && len(protocolsString) > 0 {
127 portProtocolMap, err = generate.ParseProtocols(protocolsString)
128 if err != nil {
129 return nil, err
130 }
131 }
132
133
134
135 var portString string
136 if portString, found = params["ports"]; !found {
137 portString, found = params["port"]
138 if !found && !isHeadlessService {
139 return nil, fmt.Errorf("'ports' or 'port' is a required parameter")
140 }
141 }
142
143 if portString != "" {
144 portStringSlice := strings.Split(portString, ",")
145 for i, stillPortString := range portStringSlice {
146 port, err := strconv.Atoi(stillPortString)
147 if err != nil {
148 return nil, err
149 }
150 name := servicePortName
151
152
153 if len(portStringSlice) > 1 {
154 name = fmt.Sprintf("port-%d", i+1)
155 }
156 protocol := params["protocol"]
157
158 switch {
159 case len(protocol) == 0 && len(portProtocolMap) == 0:
160
161 protocol = "TCP"
162 case len(protocol) > 0 && len(portProtocolMap) > 0:
163
164
165 case len(protocol) == 0 && len(portProtocolMap) > 0:
166
167 protocol = "TCP"
168 if exposeProtocol, found := portProtocolMap[stillPortString]; found {
169 protocol = exposeProtocol
170 }
171 }
172 ports = append(ports, v1.ServicePort{
173 Name: name,
174 Port: int32(port),
175 Protocol: v1.Protocol(protocol),
176 })
177 }
178 }
179
180 service := v1.Service{
181 ObjectMeta: metav1.ObjectMeta{
182 Name: name,
183 Labels: labels,
184 },
185 Spec: v1.ServiceSpec{
186 Selector: selector,
187 Ports: ports,
188 },
189 }
190 targetPortString := params["target-port"]
191 if len(targetPortString) == 0 {
192 targetPortString = params["container-port"]
193 }
194 if len(targetPortString) > 0 {
195 var targetPort intstr.IntOrString
196 if portNum, err := strconv.Atoi(targetPortString); err != nil {
197 targetPort = intstr.FromString(targetPortString)
198 } else {
199 targetPort = intstr.FromInt32(int32(portNum))
200 }
201
202 for i := range service.Spec.Ports {
203 service.Spec.Ports[i].TargetPort = targetPort
204 }
205 } else {
206
207
208 for i := range service.Spec.Ports {
209 port := service.Spec.Ports[i].Port
210 service.Spec.Ports[i].TargetPort = intstr.FromInt32(port)
211 }
212 }
213 if len(params["external-ip"]) > 0 {
214 service.Spec.ExternalIPs = []string{params["external-ip"]}
215 }
216 if len(params["type"]) != 0 {
217 service.Spec.Type = v1.ServiceType(params["type"])
218 }
219 if service.Spec.Type == v1.ServiceTypeLoadBalancer {
220 service.Spec.LoadBalancerIP = params["load-balancer-ip"]
221 }
222 if len(params["session-affinity"]) != 0 {
223 switch v1.ServiceAffinity(params["session-affinity"]) {
224 case v1.ServiceAffinityNone:
225 service.Spec.SessionAffinity = v1.ServiceAffinityNone
226 case v1.ServiceAffinityClientIP:
227 service.Spec.SessionAffinity = v1.ServiceAffinityClientIP
228 default:
229 return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"])
230 }
231 }
232 if len(params["cluster-ip"]) != 0 {
233 if params["cluster-ip"] == "None" {
234 service.Spec.ClusterIP = v1.ClusterIPNone
235 } else {
236 service.Spec.ClusterIP = params["cluster-ip"]
237 }
238 }
239 return &service, nil
240 }
241
View as plain text