123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /*
- Copyright 2014 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 kubectl
- import (
- "fmt"
- "strconv"
- "strings"
- "k8s.io/kubernetes/pkg/api"
- "k8s.io/kubernetes/pkg/runtime"
- "k8s.io/kubernetes/pkg/util/intstr"
- )
- // The only difference between ServiceGeneratorV1 and V2 is that the service port is named "default" in V1, while it is left unnamed in V2.
- type ServiceGeneratorV1 struct{}
- func (ServiceGeneratorV1) ParamNames() []GeneratorParam {
- return paramNames()
- }
- func (ServiceGeneratorV1) Generate(params map[string]interface{}) (runtime.Object, error) {
- params["port-name"] = "default"
- return generate(params)
- }
- type ServiceGeneratorV2 struct{}
- func (ServiceGeneratorV2) ParamNames() []GeneratorParam {
- return paramNames()
- }
- func (ServiceGeneratorV2) Generate(params map[string]interface{}) (runtime.Object, error) {
- return generate(params)
- }
- func paramNames() []GeneratorParam {
- return []GeneratorParam{
- {"default-name", true},
- {"name", false},
- {"selector", true},
- // port will be used if a user specifies --port OR the exposed object
- // has one port
- {"port", false},
- // ports will be used iff a user doesn't specify --port AND the
- // exposed object has multiple ports
- {"ports", false},
- {"labels", false},
- {"external-ip", false},
- {"create-external-load-balancer", false},
- {"load-balancer-ip", false},
- {"type", false},
- {"protocol", false},
- // protocols will be used to keep port-protocol mapping derived from
- // exposed object
- {"protocols", false},
- {"container-port", false}, // alias of target-port
- {"target-port", false},
- {"port-name", false},
- {"session-affinity", false},
- {"cluster-ip", false},
- }
- }
- func generate(genericParams map[string]interface{}) (runtime.Object, error) {
- params := map[string]string{}
- for key, value := range genericParams {
- strVal, isString := value.(string)
- if !isString {
- return nil, fmt.Errorf("expected string, saw %v for '%s'", value, key)
- }
- params[key] = strVal
- }
- selectorString, found := params["selector"]
- if !found || len(selectorString) == 0 {
- return nil, fmt.Errorf("'selector' is a required parameter.")
- }
- selector, err := ParseLabels(selectorString)
- if err != nil {
- return nil, err
- }
- labelsString, found := params["labels"]
- var labels map[string]string
- if found && len(labelsString) > 0 {
- labels, err = ParseLabels(labelsString)
- if err != nil {
- return nil, err
- }
- }
- name, found := params["name"]
- if !found || len(name) == 0 {
- name, found = params["default-name"]
- if !found || len(name) == 0 {
- return nil, fmt.Errorf("'name' is a required parameter.")
- }
- }
- ports := []api.ServicePort{}
- servicePortName, found := params["port-name"]
- if !found {
- // Leave the port unnamed.
- servicePortName = ""
- }
- protocolsString, found := params["protocols"]
- var portProtocolMap map[string]string
- if found && len(protocolsString) > 0 {
- portProtocolMap, err = ParseProtocols(protocolsString)
- if err != nil {
- return nil, err
- }
- }
- // ports takes precedence over port since it will be
- // specified only when the user hasn't specified a port
- // via --port and the exposed object has multiple ports.
- var portString string
- if portString, found = params["ports"]; !found {
- portString, found = params["port"]
- if !found {
- return nil, fmt.Errorf("'port' is a required parameter.")
- }
- }
- portStringSlice := strings.Split(portString, ",")
- for i, stillPortString := range portStringSlice {
- port, err := strconv.Atoi(stillPortString)
- if err != nil {
- return nil, err
- }
- name := servicePortName
- // If we are going to assign multiple ports to a service, we need to
- // generate a different name for each one.
- if len(portStringSlice) > 1 {
- name = fmt.Sprintf("port-%d", i+1)
- }
- protocol := params["protocol"]
- switch {
- case len(protocol) == 0 && len(portProtocolMap) == 0:
- // Default to TCP, what the flag was doing previously.
- protocol = "TCP"
- case len(protocol) > 0 && len(portProtocolMap) > 0:
- // User has specified the --protocol while exposing a multiprotocol resource
- // We should stomp multiple protocols with the one specified ie. do nothing
- case len(protocol) == 0 && len(portProtocolMap) > 0:
- // no --protocol and we expose a multiprotocol resource
- protocol = "TCP" // have the default so we can stay sane
- if exposeProtocol, found := portProtocolMap[stillPortString]; found {
- protocol = exposeProtocol
- }
- }
- ports = append(ports, api.ServicePort{
- Name: name,
- Port: int32(port),
- Protocol: api.Protocol(protocol),
- })
- }
- service := api.Service{
- ObjectMeta: api.ObjectMeta{
- Name: name,
- Labels: labels,
- },
- Spec: api.ServiceSpec{
- Selector: selector,
- Ports: ports,
- },
- }
- targetPortString := params["target-port"]
- if len(targetPortString) == 0 {
- targetPortString = params["container-port"]
- }
- if len(targetPortString) > 0 {
- var targetPort intstr.IntOrString
- if portNum, err := strconv.Atoi(targetPortString); err != nil {
- targetPort = intstr.FromString(targetPortString)
- } else {
- targetPort = intstr.FromInt(portNum)
- }
- // Use the same target-port for every port
- for i := range service.Spec.Ports {
- service.Spec.Ports[i].TargetPort = targetPort
- }
- } else {
- // If --target-port or --container-port haven't been specified, this
- // should be the same as Port
- for i := range service.Spec.Ports {
- port := service.Spec.Ports[i].Port
- service.Spec.Ports[i].TargetPort = intstr.FromInt(int(port))
- }
- }
- if params["create-external-load-balancer"] == "true" {
- service.Spec.Type = api.ServiceTypeLoadBalancer
- }
- if len(params["external-ip"]) > 0 {
- service.Spec.ExternalIPs = []string{params["external-ip"]}
- }
- if len(params["type"]) != 0 {
- service.Spec.Type = api.ServiceType(params["type"])
- }
- if service.Spec.Type == api.ServiceTypeLoadBalancer {
- service.Spec.LoadBalancerIP = params["load-balancer-ip"]
- }
- if len(params["session-affinity"]) != 0 {
- switch api.ServiceAffinity(params["session-affinity"]) {
- case api.ServiceAffinityNone:
- service.Spec.SessionAffinity = api.ServiceAffinityNone
- case api.ServiceAffinityClientIP:
- service.Spec.SessionAffinity = api.ServiceAffinityClientIP
- default:
- return nil, fmt.Errorf("unknown session affinity: %s", params["session-affinity"])
- }
- }
- if len(params["cluster-ip"]) != 0 {
- if params["cluster-ip"] == "None" {
- service.Spec.ClusterIP = api.ClusterIPNone
- } else {
- service.Spec.ClusterIP = params["cluster-ip"]
- }
- }
- return &service, nil
- }
|