// protobuf struct to kubenetes Service func ServiceTokubenetStruct(args *types.Service) *api.Service { // 建立配置文件 todata := &api.Service{ TypeMeta: api_unversioned.TypeMeta{ Kind: "Service", APIVersion: types.ApiVersion, }, ObjectMeta: api.ObjectMeta{ Name: args.Name, Labels: args.Labels, }, Spec: api.ServiceSpec{}, Status: api.ServiceStatus{}, } // 解析转换容器信息 var ports []api.ServicePort = make([]api.ServicePort, len(args.Port)) for k1, v := range args.Port { // 解析转换端口信息 ports[k1] = api.ServicePort{ Name: v.Name, Protocol: api.Protocol(v.Protocol), Port: int(v.Port), TargetPort: intstr.IntOrString{ IntVal: v.TargetPort, }, NodePort: int(v.NodePort), } } todata.Spec.Ports = ports return todata }
func buildContainerPorts(userPorts []interface{}) []api.ContainerPort { if len(userPorts) == 0 { return nil } var ports []api.ContainerPort for _, p := range userPorts { userPort := p.(map[string]interface{}) port := api.ContainerPort{ ContainerPort: userPort["container_port"].(int), } if _, ok := userPort["host_port"]; ok { port.HostPort = userPort["host_port"].(int) } if _, ok := userPort["name"]; ok { port.Name = userPort["name"].(string) } if _, ok := userPort["protocol"]; ok { port.Protocol = api.Protocol(userPort["protocol"].(string)) } if _, ok := userPort["host_ip"]; ok { port.HostIP = userPort["host_ip"].(string) } ports = append(ports, port) } return ports }
func ServicePorts(srvcPorts []interface{}) []api.ServicePort { if len(srvcPorts) == 0 { return nil } var ports []api.ServicePort for _, p := range srvcPorts { userPort := p.(map[string]interface{}) srvcPort := api.ServicePort{} if _, ok := userPort["name"]; ok { srvcPort.Name = userPort["name"].(string) } if _, ok := userPort["protocol"]; ok { srvcPort.Protocol = api.Protocol(userPort["protocol"].(string)) } if _, ok := userPort["port"]; ok { srvcPort.Port = userPort["port"].(int) } if _, ok := userPort["node_port"]; ok { srvcPort.NodePort = userPort["node_port"].(int) } ports = append(ports, srvcPort) } return ports }
func fakeDeploymentConfig(name string, containers ...containerDesc) *deployapi.DeploymentConfig { specContainers := []kapi.Container{} for _, c := range containers { container := kapi.Container{ Name: c.name, } container.Ports = []kapi.ContainerPort{} for _, p := range c.ports { container.Ports = append(container.Ports, kapi.ContainerPort{ Name: fmt.Sprintf("port-%d-%s", p.port, p.protocol), ContainerPort: p.port, Protocol: kapi.Protocol(p.protocol), }) } specContainers = append(specContainers, container) } return &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, Spec: deployapi.DeploymentConfigSpec{ Replicas: 1, Selector: map[string]string{"name": "test"}, Template: &kapi.PodTemplateSpec{ Spec: kapi.PodSpec{ Containers: specContainers, }, }, }, } }
func buildService(name, namespace, clusterIP, protocol string, port int) *api.Service { return &api.Service{ ObjectMeta: api.ObjectMeta{Name: name, Namespace: namespace}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{{ Protocol: api.Protocol(protocol), Port: int32(port), }}, ClusterIP: clusterIP, }, } }
func writeContainerPort(m map[string]interface{}, item *api.ContainerPort) { if x, ok := m["name"].(string); ok { item.Name = x } if x, ok := m["host_port"].(int); ok { item.HostPort = x } if x, ok := m["host_ip"].(string); ok { item.HostIP = x } if x, ok := m["container_port"].(int); ok { item.ContainerPort = x } if x, ok := m["protocol"].(string); ok { item.Protocol = api.Protocol(x) } }
func (s ServiceCommonGeneratorV1) StructuredGenerate() (runtime.Object, error) { err := s.validate() if err != nil { return nil, err } ports := []api.ServicePort{} for _, tcpString := range s.TCP { port, targetPort, err := parsePorts(tcpString) if err != nil { return nil, err } portName := strings.Replace(tcpString, ":", "-", -1) ports = append(ports, api.ServicePort{ Name: portName, Port: port, TargetPort: targetPort, Protocol: api.Protocol("TCP"), NodePort: int32(s.NodePort), }) } // setup default label and selector labels := map[string]string{} labels["app"] = s.Name selector := map[string]string{} selector["app"] = s.Name service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: s.Name, Labels: labels, }, Spec: api.ServiceSpec{ Type: api.ServiceType(s.Type), Selector: selector, Ports: ports, ExternalName: s.ExternalName, }, } if len(s.ClusterIP) > 0 { service.Spec.ClusterIP = s.ClusterIP } return &service, nil }
func expectedService(name string, ports ...portDesc) *kapi.Service { servicePorts := []kapi.ServicePort{} for _, p := range ports { servicePorts = append(servicePorts, kapi.ServicePort{ // Name is derived purely from the port and protocol, ignoring the container port name Name: fmt.Sprintf("%d-%s", p.port, p.protocol), Port: p.port, Protocol: kapi.Protocol(p.protocol), TargetPort: intstr.FromInt(p.port), }) } return &kapi.Service{ ObjectMeta: kapi.ObjectMeta{ Name: name, }, Spec: kapi.ServiceSpec{ Selector: map[string]string{"name": "test"}, Ports: servicePorts, }, } }
// protobuf struct to kubenetes pod func PodToKubeStruct(args *types.Pod) *api.Pod { // 建立配置文件 todata := &api.Pod{ TypeMeta: api_unversioned.TypeMeta{ Kind: "Pod", APIVersion: types.ApiVersion, }, ObjectMeta: api.ObjectMeta{ Name: args.Name, Labels: args.Labels, }, Spec: api.PodSpec{}, Status: api.PodStatus{}, } // 解析转换容器信息 var container []api.Container = make([]api.Container, len(args.Containers)) for k1, v := range args.Containers { // 解析转换端口信息 var containerPort = make([]api.ContainerPort, len(v.Port)) for k2, port := range v.Port { containerPort[k2] = api.ContainerPort{ Protocol: api.Protocol(port.Protocol), ContainerPort: int(port.ContainerPort), } } // 写入镜像信息 container[k1] = api.Container{ Name: v.Name, Image: v.Image, Ports: containerPort, } } todata.Spec.Containers = container return todata }
func (testServiceGenerator) 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 } labelsString, found := params["labels"] var labels map[string]string var err error if found && len(labelsString) > 0 { labels, err = kubectl.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.") } } portString, found := params["port"] if !found { return nil, fmt.Errorf("'port' is a required parameter.") } port, err := strconv.Atoi(portString) if err != nil { return nil, err } servicePortName, found := params["port-name"] if !found { // Leave the port unnamed. servicePortName = "" } service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: servicePortName, Port: port, Protocol: api.Protocol(params["protocol"]), }, }, }, } targetPort, found := params["target-port"] if !found { targetPort, found = params["container-port"] } if found && len(targetPort) > 0 { if portNum, err := strconv.Atoi(targetPort); err != nil { service.Spec.Ports[0].TargetPort = intstr.FromString(targetPort) } else { service.Spec.Ports[0].TargetPort = intstr.FromInt(portNum) } } else { service.Spec.Ports[0].TargetPort = intstr.FromInt(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 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"]) } } return &service, nil }
func TestImageRefDeployableContainerPorts(t *testing.T) { tests := []struct { name string inputPorts map[string]struct{} expectedPorts map[int]string expectError bool noConfig bool }{ { name: "tcp implied, individual ports", inputPorts: map[string]struct{}{ "123": {}, "456": {}, }, expectedPorts: map[int]string{ 123: "TCP", 456: "TCP", }, expectError: false, }, { name: "tcp implied, multiple ports", inputPorts: map[string]struct{}{ "123 456": {}, "678 1123": {}, }, expectedPorts: map[int]string{ 123: "TCP", 678: "TCP", 456: "TCP", 1123: "TCP", }, expectError: false, }, { name: "tcp and udp, individual ports", inputPorts: map[string]struct{}{ "123/tcp": {}, "456/udp": {}, }, expectedPorts: map[int]string{ 123: "TCP", 456: "UDP", }, expectError: false, }, { name: "tcp implied, multiple ports", inputPorts: map[string]struct{}{ "123/tcp 456/udp": {}, "678/udp 1123/tcp": {}, }, expectedPorts: map[int]string{ 123: "TCP", 456: "UDP", 678: "UDP", 1123: "TCP", }, expectError: false, }, { name: "invalid format", inputPorts: map[string]struct{}{ "123/tcp abc": {}, }, expectedPorts: map[int]string{}, expectError: true, }, { name: "no image config", expectedPorts: map[int]string{}, expectError: false, noConfig: true, }, } for _, test := range tests { imageRef := &ImageRef{ Reference: imageapi.DockerImageReference{ Namespace: "test", Name: "image", Tag: imageapi.DefaultImageTag, }, Info: &imageapi.DockerImage{ Config: &imageapi.DockerConfig{ ExposedPorts: test.inputPorts, }, }, } if test.noConfig { imageRef.Info.Config = nil } container, _, err := imageRef.DeployableContainer() if err != nil && !test.expectError { t.Errorf("%s: unexpected error: %v", test.name, err) continue } if err == nil && test.expectError { t.Errorf("%s: got no error and expected an error", test.name) continue } if test.expectError { continue } remaining := test.expectedPorts for _, port := range container.Ports { proto, ok := remaining[port.ContainerPort] if !ok { t.Errorf("%s: got unexpected port: %v", test.name, port) continue } if kapi.Protocol(proto) != port.Protocol { t.Errorf("%s: got unexpected protocol %s for port %v", test.name, port.Protocol, port) } delete(remaining, port.ContainerPort) } if len(remaining) > 0 { t.Errorf("%s: did not find expected ports: %#v", test.name, remaining) } } }
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, found := params["target-port"] if !found { targetPortString, found = params["container-port"] } if found && 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"]) } } return &service, nil }
// DeployableContainer sets up a container for the image ready for deployment func (r *ImageRef) DeployableContainer() (container *kapi.Container, triggers []deployapi.DeploymentTriggerPolicy, err error) { name, ok := r.SuggestName() if !ok { return nil, nil, fmt.Errorf("unable to suggest a container name for the image %q", r.String()) } if r.AsImageStream { tag := r.Tag if len(tag) == 0 { tag = imageapi.DefaultImageTag } imageChangeParams := &deployapi.DeploymentTriggerImageChangeParams{ Automatic: true, ContainerNames: []string{name}, Tag: tag, } if r.Stream != nil { imageChangeParams.From = kapi.ObjectReference{ Kind: "ImageStream", Name: r.Stream.Name, Namespace: r.Stream.Namespace, } } else { imageChangeParams.From = kapi.ObjectReference{ Kind: "ImageStream", Name: name, } } triggers = []deployapi.DeploymentTriggerPolicy{ { Type: deployapi.DeploymentTriggerOnImageChange, ImageChangeParams: imageChangeParams, }, } } container = &kapi.Container{ Name: name, Image: r.String(), } // If imageInfo present, append ports if r.Info != nil && r.Info.Config != nil { ports := []string{} // ExposedPorts can consist of multiple space-separated ports for exposed := range r.Info.Config.ExposedPorts { ports = append(ports, strings.Split(exposed, " ")...) } for _, sp := range ports { p := docker.Port(sp) port, err := strconv.Atoi(p.Port()) if err != nil { return nil, nil, fmt.Errorf("failed to parse port %q: %v", p.Port(), err) } container.Ports = append(container.Ports, kapi.ContainerPort{ ContainerPort: port, Protocol: kapi.Protocol(strings.ToUpper(p.Proto())), }) } // Create volume mounts with names based on container name maxDigits := len(fmt.Sprintf("%d", len(r.Info.Config.Volumes))) baseName := namer.GetName(container.Name, volumeNameInfix, kvalidation.LabelValueMaxLength-maxDigits-1) i := 1 for volume := range r.Info.Config.Volumes { r.HasEmptyDir = true container.VolumeMounts = append(container.VolumeMounts, kapi.VolumeMount{ Name: fmt.Sprintf("%s-%d", baseName, i), ReadOnly: false, MountPath: volume, }) i++ } // TODO: Append environment variables } return container, triggers, nil }
func TestRunExposeServiceFromFile(t *testing.T) { test := struct { calls map[string]string input runtime.Object flags map[string]string output runtime.Object expected string status int }{ calls: map[string]string{ "GET": "/namespaces/test/services/redis-master", "POST": "/namespaces/test/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"app": "go"}, }, }, flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("UDP"), Port: 14, }, }, Selector: map[string]string{"func": "stream"}, }, }, status: 200, } f, tf, codec := NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &client.FakeRESTClient{ Codec: codec, Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case p == test.calls[m] && m == "GET": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.input)}, nil case p == test.calls[m] && m == "POST": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.output)}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) cmd := NewCmdExposeService(f, buf) cmd.SetOutput(buf) for flag, value := range test.flags { cmd.Flags().Set(flag, value) } cmd.Flags().Set("filename", "../../../examples/guestbook/redis-master-service.yaml") cmd.Run(cmd, []string{}) if len(test.expected) > 0 { out := buf.String() if !strings.Contains(out, test.expected) { t.Errorf("unexpected output: %s", out) } } }
func TestBuildListener(t *testing.T) { tests := []struct { name string lbPort int64 portName string instancePort int64 backendProtocolAnnotation string certAnnotation string sslPortAnnotation string expectError bool lbProtocol string instanceProtocol string certID string }{ { "No cert or BE protocol annotation, passthrough", 80, "", 7999, "", "", "", false, "tcp", "tcp", "", }, { "Cert annotation without BE protocol specified, SSL->TCP", 80, "", 8000, "", "cert", "", false, "ssl", "tcp", "cert", }, { "BE protocol without cert annotation, passthrough", 443, "", 8001, "https", "", "", false, "tcp", "tcp", "", }, { "Invalid cert annotation, bogus backend protocol", 443, "", 8002, "bacon", "foo", "", true, "tcp", "tcp", "", }, { "Invalid cert annotation, protocol followed by equal sign", 443, "", 8003, "http=", "=", "", true, "tcp", "tcp", "", }, { "HTTPS->HTTPS", 443, "", 8004, "https", "cert", "", false, "https", "https", "cert", }, { "HTTPS->HTTP", 443, "", 8005, "http", "cert", "", false, "https", "http", "cert", }, { "SSL->SSL", 443, "", 8006, "ssl", "cert", "", false, "ssl", "ssl", "cert", }, { "SSL->TCP", 443, "", 8007, "tcp", "cert", "", false, "ssl", "tcp", "cert", }, { "Port in whitelist", 1234, "", 8008, "tcp", "cert", "1234,5678", false, "ssl", "tcp", "cert", }, { "Port not in whitelist, passthrough", 443, "", 8009, "tcp", "cert", "1234,5678", false, "tcp", "tcp", "", }, { "Named port in whitelist", 1234, "bar", 8010, "tcp", "cert", "foo,bar", false, "ssl", "tcp", "cert", }, { "Named port not in whitelist, passthrough", 443, "", 8011, "tcp", "cert", "foo,bar", false, "tcp", "tcp", "", }, { "HTTP->HTTP", 80, "", 8012, "http", "", "", false, "http", "http", "", }, } for _, test := range tests { t.Logf("Running test case %s", test.name) annotations := make(map[string]string) if test.backendProtocolAnnotation != "" { annotations[ServiceAnnotationLoadBalancerBEProtocol] = test.backendProtocolAnnotation } if test.certAnnotation != "" { annotations[ServiceAnnotationLoadBalancerCertificate] = test.certAnnotation } ports := getPortSets(test.sslPortAnnotation) l, err := buildListener(api.ServicePort{ NodePort: int32(test.instancePort), Port: int32(test.lbPort), Name: test.portName, Protocol: api.Protocol("tcp"), }, annotations, ports) if test.expectError { if err == nil { t.Errorf("Should error for case %s", test.name) } } else { if err != nil { t.Errorf("Should succeed for case: %s, got %v", test.name, err) } else { var cert *string if test.certID != "" { cert = &test.certID } expected := &elb.Listener{ InstancePort: &test.instancePort, InstanceProtocol: &test.instanceProtocol, LoadBalancerPort: &test.lbPort, Protocol: &test.lbProtocol, SSLCertificateId: cert, } if !reflect.DeepEqual(l, expected) { t.Errorf("Incorrect listener (%v vs expected %v) for case: %s", l, expected, test.name) } } } } }
func generate(params map[string]string) (runtime.Object, error) { 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.") } } portString, found := params["port"] if !found { return nil, fmt.Errorf("'port' is a required parameter.") } port, err := strconv.Atoi(portString) if err != nil { return nil, err } servicePortName, found := params["port-name"] if !found { // Leave the port unnamed. servicePortName = "" } service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.ServiceSpec{ Selector: selector, Ports: []api.ServicePort{ { Name: servicePortName, Port: port, Protocol: api.Protocol(params["protocol"]), }, }, }, } targetPort, found := params["target-port"] if !found { targetPort, found = params["container-port"] } if found && len(targetPort) > 0 { if portNum, err := strconv.Atoi(targetPort); err != nil { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromString(targetPort) } else { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromInt(portNum) } } else { service.Spec.Ports[0].TargetPort = util.NewIntOrStringFromInt(port) } if params["create-external-load-balancer"] == "true" { service.Spec.Type = api.ServiceTypeLoadBalancer } if len(params["public-ip"]) != 0 { service.Spec.DeprecatedPublicIPs = []string{params["public-ip"]} } if len(params["type"]) != 0 { service.Spec.Type = api.ServiceType(params["type"]) } return &service, nil }
func TestRunExposeService(t *testing.T) { tests := []struct { name string args []string ns string calls map[string]string input runtime.Object flags map[string]string output runtime.Object expected string status int podSelector string }{ { name: "expose-service-from-service-no-selector", args: []string{"service", "baz"}, ns: "test", calls: map[string]string{ "GET": "/namespaces/test/services/baz", "POST": "/namespaces/test/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"app": "go"}, }, }, podSelector: "app=go", flags: map[string]string{"protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("UDP"), Port: 14, }, }, Selector: map[string]string{"app": "go"}, }, }, status: 200, }, { name: "expose-service-from-service", args: []string{"service", "baz"}, ns: "test", calls: map[string]string{ "GET": "/namespaces/test/services/baz", "POST": "/namespaces/test/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"app": "go"}, }, }, flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("UDP"), Port: 14, }, }, Selector: map[string]string{"func": "stream"}, }, }, status: 200, }, { name: "no-name-passed-from-the-cli", args: []string{"service", "mayor"}, ns: "default", calls: map[string]string{ "GET": "/namespaces/default/services/mayor", "POST": "/namespaces/default/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "mayor", Namespace: "default", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"run": "this"}, }, }, // No --name flag specified below. Service will use the rc's name passed via the 'default-name' parameter flags: map[string]string{"selector": "run=this", "port": "80", "labels": "runas=amayor"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "mayor", Namespace: "default", ResourceVersion: "12", Labels: map[string]string{"runas": "amayor"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("TCP"), Port: 80, }, }, Selector: map[string]string{"run": "this"}, }, }, status: 200, }, { name: "expose-external-service", args: []string{"service", "baz"}, ns: "test", calls: map[string]string{ "GET": "/namespaces/test/services/baz", "POST": "/namespaces/test/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"app": "go"}, }, }, flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "create-external-load-balancer": "true"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("UDP"), Port: 14, TargetPort: util.NewIntOrStringFromInt(14), }, }, Selector: map[string]string{"func": "stream"}, Type: api.ServiceTypeLoadBalancer, }, }, status: 200, }, { name: "expose-external-affinity-service", args: []string{"service", "baz"}, ns: "test", calls: map[string]string{ "GET": "/namespaces/test/services/baz", "POST": "/namespaces/test/services", }, input: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "12"}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"app": "go"}, }, }, flags: map[string]string{"selector": "func=stream", "protocol": "UDP", "port": "14", "name": "foo", "labels": "svc=test", "create-external-load-balancer": "true", "session-affinity": "ClientIP"}, output: &api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "12", Labels: map[string]string{"svc": "test"}}, TypeMeta: api.TypeMeta{Kind: "Service", APIVersion: "v1"}, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ { Name: "default", Protocol: api.Protocol("UDP"), Port: 14, TargetPort: util.NewIntOrStringFromInt(14), }, }, Selector: map[string]string{"func": "stream"}, Type: api.ServiceTypeLoadBalancer, SessionAffinity: api.ServiceAffinityClientIP, }, }, status: 200, }, } for _, test := range tests { f, tf, codec := NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ Codec: codec, Client: fake.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { switch p, m := req.URL.Path, req.Method; { case p == test.calls[m] && m == "GET": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.input)}, nil case p == test.calls[m] && m == "POST": return &http.Response{StatusCode: test.status, Body: objBody(codec, test.output)}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = test.ns f.PodSelectorForObject = func(obj runtime.Object) (string, error) { return test.podSelector, nil } buf := bytes.NewBuffer([]byte{}) cmd := NewCmdExposeService(f, buf) cmd.SetOutput(buf) for flag, value := range test.flags { cmd.Flags().Set(flag, value) } cmd.Run(cmd, test.args) if len(test.expected) > 0 { out := buf.String() if !strings.Contains(out, test.expected) { t.Errorf("%s: unexpected output: %s", test.name, out) } } } }