func TestSetDefaulServiceTargetPort(t *testing.T) { in := &versioned.Service{Spec: versioned.ServiceSpec{Ports: []versioned.ServicePort{{Port: 1234}}}} obj := roundTrip(t, runtime.Object(in)) out := obj.(*versioned.Service) if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(1234) { t.Errorf("Expected TargetPort to be defaulted, got %s", out.Spec.Ports[0].TargetPort) } in = &versioned.Service{Spec: versioned.ServiceSpec{Ports: []versioned.ServicePort{{Port: 1234, TargetPort: util.NewIntOrStringFromInt(5678)}}}} obj = roundTrip(t, runtime.Object(in)) out = obj.(*versioned.Service) if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(5678) { t.Errorf("Expected TargetPort to be unchanged, got %s", out.Spec.Ports[0].TargetPort) } }
func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) { ns := api.NamespaceDefault testServer, endpointsHandler := makeTestServer(t, api.NamespaceDefault, serverResponse{http.StatusOK, &api.Endpoints{ ObjectMeta: api.ObjectMeta{ ResourceVersion: "1", Name: "foo", Namespace: ns, }, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &api.ObjectReference{Kind: "Pod", Name: "pod0", Namespace: ns}}}, Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, }}) defer testServer.Close() client := client.NewOrDie(&client.Config{Host: testServer.URL, Version: testapi.Version()}) endpoints := NewEndpointController(client) addPods(endpoints.podStore.Store, api.NamespaceDefault, 1, 1) endpoints.serviceStore.Store.Add(&api.Service{ ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, Spec: api.ServiceSpec{ Selector: map[string]string{"foo": "bar"}, Ports: []api.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)}}, }, }) endpoints.syncService(ns + "/foo") endpointsHandler.ValidateRequest(t, testapi.ResourcePath("endpoints", api.NamespaceDefault, "foo"), "GET", nil) }
func TestSyncEndpointsItemsWithLabels(t *testing.T) { ns := "other" testServer, endpointsHandler := makeTestServer(t, ns, serverResponse{http.StatusOK, &api.Endpoints{}}) defer testServer.Close() client := client.NewOrDie(&client.Config{Host: testServer.URL, Version: testapi.Version()}) endpoints := NewEndpointController(client) addPods(endpoints.podStore.Store, ns, 3, 2) serviceLabels := map[string]string{"foo": "bar"} endpoints.serviceStore.Store.Add(&api.Service{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: ns, Labels: serviceLabels, }, Spec: api.ServiceSpec{ Selector: map[string]string{"foo": "bar"}, Ports: []api.ServicePort{ {Name: "port0", Port: 80, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)}, {Name: "port1", Port: 88, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8088)}, }, }, }) endpoints.syncService(ns + "/foo") expectedSubsets := []api.EndpointSubset{{ Addresses: []api.EndpointAddress{ {IP: "1.2.3.4", TargetRef: &api.ObjectReference{Kind: "Pod", Name: "pod0", Namespace: ns}}, {IP: "1.2.3.5", TargetRef: &api.ObjectReference{Kind: "Pod", Name: "pod1", Namespace: ns}}, {IP: "1.2.3.6", TargetRef: &api.ObjectReference{Kind: "Pod", Name: "pod2", Namespace: ns}}, }, Ports: []api.EndpointPort{ {Name: "port0", Port: 8080, Protocol: "TCP"}, {Name: "port1", Port: 8088, Protocol: "TCP"}, }, }} data := runtime.EncodeOrDie(testapi.Codec(), &api.Endpoints{ ObjectMeta: api.ObjectMeta{ ResourceVersion: "", Labels: serviceLabels, }, Subsets: endptspkg.SortSubsets(expectedSubsets), }) // endpointsHandler should get 2 requests - one for "GET" and the next for "POST". endpointsHandler.ValidateRequestCount(t, 2) endpointsHandler.ValidateRequest(t, testapi.ResourcePath("endpoints", ns, ""), "POST", &data) }
func (b nginxProbeBuilder) build() *api.Probe { probe := &api.Probe{ Handler: api.Handler{ HTTPGet: &api.HTTPGetAction{ Port: util.NewIntOrStringFromInt(80), Path: "/", }, }, } if b.initialDelay { probe.InitialDelaySeconds = 30 } if b.failing { probe.HTTPGet.Port = util.NewIntOrStringFromInt(81) } return probe }
func TestGetURLParts(t *testing.T) { testCases := []struct { probe *api.HTTPGetAction ok bool host string port int path string }{ {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromInt(-1), Path: ""}, false, "", -1, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString(""), Path: ""}, false, "", -1, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("-1"), Path: ""}, false, "", -1, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("not-found"), Path: ""}, false, "", -1, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("found"), Path: ""}, true, "127.0.0.1", 93, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromInt(76), Path: ""}, true, "127.0.0.1", 76, ""}, {&api.HTTPGetAction{Host: "", Port: util.NewIntOrStringFromString("118"), Path: ""}, true, "127.0.0.1", 118, ""}, {&api.HTTPGetAction{Host: "hostname", Port: util.NewIntOrStringFromInt(76), Path: "path"}, true, "hostname", 76, "path"}, } for _, test := range testCases { state := api.PodStatus{PodIP: "127.0.0.1"} container := api.Container{ Ports: []api.ContainerPort{{Name: "found", HostPort: 93}}, LivenessProbe: &api.Probe{ Handler: api.Handler{ HTTPGet: test.probe, }, }, } p, err := extractPort(test.probe.Port, container) if test.ok && err != nil { t.Errorf("Unexpected error: %v", err) } host, port, path := extractGetParams(test.probe, state, p) if !test.ok && err == nil { t.Errorf("Expected error for %+v, got %s:%d/%s", test, host, port, path) } if test.ok { if host != test.host || port != test.port || path != test.path { t.Errorf("Expected %s:%d/%s, got %s:%d/%s", test.host, test.port, test.path, host, port, path) } } } }
func TestDoRequestNewWayFile(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} reqBodyExpected, err := testapi.Codec().Encode(reqObj) if err != nil { t.Errorf("unexpected error: %v", err) } file, err := ioutil.TempFile("", "foo") if err != nil { t.Errorf("unexpected error: %v", err) } _, err = file.Write(reqBodyExpected) if err != nil { t.Errorf("unexpected error: %v", err) } expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{ Protocol: "TCP", Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "******", Password: "******"}) wasCreated := true obj, err := c.Verb("POST"). Prefix("foo/bar", "baz"). Timeout(time.Second). Body(file.Name()). Do().WasCreated(&wasCreated).Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if obj == nil { t.Error("nil obj") } else if !api.Semantic.DeepDerivative(expectedObj, obj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } if wasCreated { t.Errorf("expected object was not created") } tmpStr := string(reqBodyExpected) requestURL := testapi.ResourcePathWithPrefix("foo/bar/baz", "", "", "") requestURL += "?timeout=1s" fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } }
func TestSetDefaultServicePort(t *testing.T) { // Unchanged if set. in := &versioned.Service{Spec: versioned.ServiceSpec{ Ports: []versioned.ServicePort{ {Protocol: "UDP", Port: 9376, TargetPort: util.NewIntOrStringFromString("p")}, {Protocol: "UDP", Port: 8675, TargetPort: util.NewIntOrStringFromInt(309)}, }, }} out := roundTrip(t, runtime.Object(in)).(*versioned.Service) if out.Spec.Ports[0].Protocol != versioned.ProtocolUDP { t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Spec.Ports[0].Protocol) } if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromString("p") { t.Errorf("Expected port %d, got %s", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort) } if out.Spec.Ports[1].Protocol != versioned.ProtocolUDP { t.Errorf("Expected protocol %s, got %s", versioned.ProtocolUDP, out.Spec.Ports[1].Protocol) } if out.Spec.Ports[1].TargetPort != util.NewIntOrStringFromInt(309) { t.Errorf("Expected port %d, got %s", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort) } // Defaulted. in = &versioned.Service{Spec: versioned.ServiceSpec{ Ports: []versioned.ServicePort{ {Protocol: "", Port: 9376, TargetPort: util.NewIntOrStringFromString("")}, {Protocol: "", Port: 8675, TargetPort: util.NewIntOrStringFromInt(0)}, }, }} out = roundTrip(t, runtime.Object(in)).(*versioned.Service) if out.Spec.Ports[0].Protocol != versioned.ProtocolTCP { t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Spec.Ports[0].Protocol) } if out.Spec.Ports[0].TargetPort != util.NewIntOrStringFromInt(in.Spec.Ports[0].Port) { t.Errorf("Expected port %d, got %d", in.Spec.Ports[0].Port, out.Spec.Ports[0].TargetPort) } if out.Spec.Ports[1].Protocol != versioned.ProtocolTCP { t.Errorf("Expected protocol %s, got %s", versioned.ProtocolTCP, out.Spec.Ports[1].Protocol) } if out.Spec.Ports[1].TargetPort != util.NewIntOrStringFromInt(in.Spec.Ports[1].Port) { t.Errorf("Expected port %d, got %d", in.Spec.Ports[1].Port, out.Spec.Ports[1].TargetPort) } }
func TestGetTCPAddrParts(t *testing.T) { testCases := []struct { probe *api.TCPSocketAction ok bool host string port int }{ {&api.TCPSocketAction{Port: util.NewIntOrStringFromInt(-1)}, false, "", -1}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromString("")}, false, "", -1}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromString("-1")}, false, "", -1}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromString("not-found")}, false, "", -1}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromString("found")}, true, "1.2.3.4", 93}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromInt(76)}, true, "1.2.3.4", 76}, {&api.TCPSocketAction{Port: util.NewIntOrStringFromString("118")}, true, "1.2.3.4", 118}, } for _, test := range testCases { host := "1.2.3.4" container := api.Container{ Ports: []api.ContainerPort{{Name: "found", HostPort: 93}}, LivenessProbe: &api.Probe{ Handler: api.Handler{ TCPSocket: test.probe, }, }, } port, err := extractPort(test.probe.Port, container) if !test.ok && err == nil { t.Errorf("Expected error for %+v, got %s:%d", test, host, port) } if test.ok && err != nil { t.Errorf("Unexpected error: %v", err) } if test.ok { if host != test.host || port != test.port { t.Errorf("Expected %s:%d, got %s:%d", test.host, test.port, host, port) } } } }
// Build default config for a service (which can then be changed) func (t *WebserverTest) BuildServiceSpec() *api.Service { service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: t.ServiceName, }, Spec: api.ServiceSpec{ Selector: t.Labels, Ports: []api.ServicePort{{ Port: 80, TargetPort: util.NewIntOrStringFromInt(80), }}, }, } return service }
func TestSyncEndpointsItemsPreexistingLabelsChange(t *testing.T) { ns := "bar" testServer, endpointsHandler := makeTestServer(t, ns, serverResponse{http.StatusOK, &api.Endpoints{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: ns, ResourceVersion: "1", Labels: map[string]string{ "foo": "bar", }, }, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "6.7.8.9"}}, Ports: []api.EndpointPort{{Port: 1000}}, }}, }}) defer testServer.Close() client := client.NewOrDie(&client.Config{Host: testServer.URL, Version: testapi.Version()}) endpoints := NewEndpointController(client) addPods(endpoints.podStore.Store, ns, 1, 1) serviceLabels := map[string]string{"baz": "blah"} endpoints.serviceStore.Store.Add(&api.Service{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: ns, Labels: serviceLabels, }, Spec: api.ServiceSpec{ Selector: map[string]string{"foo": "bar"}, Ports: []api.ServicePort{{Port: 80, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(8080)}}, }, }) endpoints.syncService(ns + "/foo") data := runtime.EncodeOrDie(testapi.Codec(), &api.Endpoints{ ObjectMeta: api.ObjectMeta{ Name: "foo", Namespace: ns, ResourceVersion: "1", Labels: serviceLabels, }, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{{IP: "1.2.3.4", TargetRef: &api.ObjectReference{Kind: "Pod", Name: "pod0", Namespace: ns}}}, Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, }) endpointsHandler.ValidateRequest(t, testapi.ResourcePath("endpoints", ns, "foo"), "PUT", &data) }
func TestDoRequestNewWayObj(t *testing.T) { reqObj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} reqBodyExpected, _ := testapi.Codec().Encode(reqObj) expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{ Protocol: "TCP", Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "******", Password: "******"}) obj, err := c.Verb("POST"). Suffix("baz"). Name("bar"). Resource("foo"). LabelsSelectorParam(labels.Set{"name": "foo"}.AsSelector()). Timeout(time.Second). Body(reqObj). Do().Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if obj == nil { t.Error("nil obj") } else if !api.Semantic.DeepDerivative(expectedObj, obj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } tmpStr := string(reqBodyExpected) requestURL := testapi.ResourcePath("foo", "", "bar/baz") requestURL += "?" + api.LabelSelectorQueryParam(testapi.Version()) + "=name%3Dfoo&timeout=1s" fakeHandler.ValidateRequest(t, requestURL, "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } }
func TestDoRequestNewWay(t *testing.T) { reqBody := "request body" expectedObj := &api.Service{Spec: api.ServiceSpec{Ports: []api.ServicePort{{ Protocol: "TCP", Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345), }}}} expectedBody, _ := testapi.Codec().Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) defer testServer.Close() c := NewOrDie(&Config{Host: testServer.URL, Version: testapi.Version(), Username: "******", Password: "******"}) obj, err := c.Verb("POST"). Prefix("foo", "bar"). Suffix("baz"). Timeout(time.Second). Body([]byte(reqBody)). Do().Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if obj == nil { t.Error("nil obj") } else if !api.Semantic.DeepDerivative(expectedObj, obj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } requestURL := testapi.ResourcePathWithPrefix("foo/bar", "", "", "baz") requestURL += "?timeout=1s" fakeHandler.ValidateRequest(t, requestURL, "POST", &reqBody) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } }
func (ServiceGenerator) 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 } service := api.Service{ ObjectMeta: api.ObjectMeta{ Name: name, Labels: labels, }, Spec: api.ServiceSpec{ Selector: selector, Ports: []api.ServicePort{ { Name: "default", 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 TestGenerateService(t *testing.T) { tests := []struct { params map[string]string expected api.Service }{ { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "TCP", "container-port": "1234", }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1234), }, }, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "UDP", "container-port": "foobar", }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "UDP", TargetPort: util.NewIntOrStringFromString("foobar"), }, }, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "labels": "key1=value1,key2=value2", "name": "test", "port": "80", "protocol": "TCP", "container-port": "1234", }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", Labels: map[string]string{ "key1": "value1", "key2": "value2", }, }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "TCP", TargetPort: util.NewIntOrStringFromInt(1234), }, }, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "UDP", "container-port": "foobar", "public-ip": "1.2.3.4", }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "UDP", TargetPort: util.NewIntOrStringFromString("foobar"), }, }, DeprecatedPublicIPs: []string{"1.2.3.4"}, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "UDP", "container-port": "foobar", "public-ip": "1.2.3.4", "create-external-load-balancer": "true", }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "UDP", TargetPort: util.NewIntOrStringFromString("foobar"), }, }, Type: api.ServiceTypeLoadBalancer, DeprecatedPublicIPs: []string{"1.2.3.4"}, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "UDP", "container-port": "foobar", "type": string(api.ServiceTypeNodePort), }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "UDP", TargetPort: util.NewIntOrStringFromString("foobar"), }, }, Type: api.ServiceTypeNodePort, }, }, }, { params: map[string]string{ "selector": "foo=bar,baz=blah", "name": "test", "port": "80", "protocol": "UDP", "container-port": "foobar", "create-external-load-balancer": "true", // ignored when type is present "type": string(api.ServiceTypeNodePort), }, expected: api.Service{ ObjectMeta: api.ObjectMeta{ Name: "test", }, Spec: api.ServiceSpec{ Selector: map[string]string{ "foo": "bar", "baz": "blah", }, Ports: []api.ServicePort{ { Name: "default", Port: 80, Protocol: "UDP", TargetPort: util.NewIntOrStringFromString("foobar"), }, }, Type: api.ServiceTypeNodePort, }, }, }, } generator := ServiceGenerator{} for _, test := range tests { obj, err := generator.Generate(test.params) if !reflect.DeepEqual(obj, &test.expected) { t.Errorf("expected:\n%#v\ngot\n%#v\n", &test.expected, obj) } if err != nil { t.Errorf("unexpected error: %v", err) } } }
func TestFindPort(t *testing.T) { testCases := []struct { name string containers []api.Container port util.IntOrString expected int pass bool }{{ name: "valid int, no ports", containers: []api.Container{{}}, port: util.NewIntOrStringFromInt(93), expected: 93, pass: true, }, { name: "valid int, with ports", containers: []api.Container{{Ports: []api.ContainerPort{{ Name: "", ContainerPort: 11, Protocol: "TCP", }, { Name: "p", ContainerPort: 22, Protocol: "TCP", }}}}, port: util.NewIntOrStringFromInt(93), expected: 93, pass: true, }, { name: "valid str, no ports", containers: []api.Container{{}}, port: util.NewIntOrStringFromString("p"), expected: 0, pass: false, }, { name: "valid str, one ctr with ports", containers: []api.Container{{Ports: []api.ContainerPort{{ Name: "", ContainerPort: 11, Protocol: "UDP", }, { Name: "p", ContainerPort: 22, Protocol: "TCP", }, { Name: "q", ContainerPort: 33, Protocol: "TCP", }}}}, port: util.NewIntOrStringFromString("q"), expected: 33, pass: true, }, { name: "valid str, two ctr with ports", containers: []api.Container{{}, {Ports: []api.ContainerPort{{ Name: "", ContainerPort: 11, Protocol: "UDP", }, { Name: "p", ContainerPort: 22, Protocol: "TCP", }, { Name: "q", ContainerPort: 33, Protocol: "TCP", }}}}, port: util.NewIntOrStringFromString("q"), expected: 33, pass: true, }} for _, tc := range testCases { port, err := findPort(&api.Pod{Spec: api.PodSpec{Containers: tc.containers}}, &api.ServicePort{Protocol: "TCP", TargetPort: tc.port}) if err != nil && tc.pass { t.Errorf("unexpected error for %s: %v", tc.name, err) } if err == nil && !tc.pass { t.Errorf("unexpected non-error for %s: %d", tc.name, port) } if port != tc.expected { t.Errorf("wrong result for %s: expected %d, got %d", tc.name, tc.expected, port) } } }
} defer func() { err := c.Services(ns).Delete(serviceName) Expect(err).NotTo(HaveOccurred()) }() service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: serviceName, }, Spec: api.ServiceSpec{ Selector: labels, Ports: []api.ServicePort{{ Port: 80, TargetPort: util.NewIntOrStringFromInt(80), }}, }, } _, err := c.Services(ns).Create(service) Expect(err).NotTo(HaveOccurred()) validateEndpointsOrFail(c, ns, serviceName, map[string][]int{}) var names []string defer func() { for _, name := range names { err := c.Pods(ns).Delete(name, nil) Expect(err).NotTo(HaveOccurred()) } }()
func addDefaultingFuncs() { api.Scheme.AddDefaultingFuncs( func(obj *ReplicationController) { var labels map[string]string if obj.Spec.Template != nil { labels = obj.Spec.Template.Labels } // TODO: support templates defined elsewhere when we support them in the API if labels != nil { if len(obj.Spec.Selector) == 0 { obj.Spec.Selector = labels } if len(obj.Labels) == 0 { obj.Labels = labels } } if obj.Spec.Replicas == nil { obj.Spec.Replicas = new(int) *obj.Spec.Replicas = 1 } }, func(obj *Volume) { if util.AllPtrFieldsNil(&obj.VolumeSource) { obj.VolumeSource = VolumeSource{ EmptyDir: &EmptyDirVolumeSource{}, } } }, func(obj *ContainerPort) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } }, func(obj *Container) { if obj.ImagePullPolicy == "" { // TODO(dchen1107): Move ParseImageName code to pkg/util parts := strings.Split(obj.Image, ":") // Check image tag if parts[len(parts)-1] == "latest" { obj.ImagePullPolicy = PullAlways } else { obj.ImagePullPolicy = PullIfNotPresent } } if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } }, func(obj *ServiceSpec) { if obj.SessionAffinity == "" { obj.SessionAffinity = ServiceAffinityNone } if obj.Type == "" { obj.Type = ServiceTypeClusterIP } for i := range obj.Ports { sp := &obj.Ports[i] if sp.Protocol == "" { sp.Protocol = ProtocolTCP } if sp.TargetPort == util.NewIntOrStringFromInt(0) || sp.TargetPort == util.NewIntOrStringFromString("") { sp.TargetPort = util.NewIntOrStringFromInt(sp.Port) } } }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } if obj.RestartPolicy == "" { obj.RestartPolicy = RestartPolicyAlways } if obj.HostNetwork { defaultHostNetworkPorts(&obj.Containers) } }, func(obj *Probe) { if obj.TimeoutSeconds == 0 { obj.TimeoutSeconds = 1 } }, func(obj *Secret) { if obj.Type == "" { obj.Type = SecretTypeOpaque } }, func(obj *PersistentVolume) { if obj.Status.Phase == "" { obj.Status.Phase = VolumePending } if obj.Spec.PersistentVolumeReclaimPolicy == "" { obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain } }, func(obj *PersistentVolumeClaim) { if obj.Status.Phase == "" { obj.Status.Phase = ClaimPending } }, func(obj *Endpoints) { for i := range obj.Subsets { ss := &obj.Subsets[i] for i := range ss.Ports { ep := &ss.Ports[i] if ep.Protocol == "" { ep.Protocol = ProtocolTCP } } } }, func(obj *HTTPGetAction) { if obj.Path == "" { obj.Path = "/" } }, func(obj *NamespaceStatus) { if obj.Phase == "" { obj.Phase = NamespaceActive } }, func(obj *Node) { if obj.Spec.ExternalID == "" { obj.Spec.ExternalID = obj.Name } }, func(obj *ObjectFieldSelector) { if obj.APIVersion == "" { obj.APIVersion = "v1" } }, ) }
func main() { flag.Parse() glog.Infof("Starting cauldron soak test with queries=%d podsPerNode=%d upTo=%d maxPar=%d", *queriesAverage, *podsPerNode, *upTo, *maxPar) c, err := client.NewInCluster() if err != nil { glog.Fatalf("Failed to make client: %v", err) } var nodes *api.NodeList for start := time.Now(); time.Since(start) < nodeListTimeout; time.Sleep(2 * time.Second) { nodes, err = c.Nodes().List(labels.Everything(), fields.Everything()) if err == nil { break } glog.Warningf("Failed to list nodes: %v", err) } if err != nil { glog.Fatalf("Giving up trying to list nodes: %v", err) } if len(nodes.Items) == 0 { glog.Fatalf("Failed to find any nodes.") } glog.Infof("Found %d nodes on this cluster:", len(nodes.Items)) for i, node := range nodes.Items { glog.Infof("%d: %s", i, node.Name) } queries := *queriesAverage * len(nodes.Items) * *podsPerNode // Create a uniquely named namespace. got, err := c.Namespaces().Create(&api.Namespace{ObjectMeta: api.ObjectMeta{GenerateName: "serve-hostnames-"}}) if err != nil { glog.Fatalf("Failed to create namespace: %v", err) } ns := got.Name defer func(ns string) { if err := c.Namespaces().Delete(ns); err != nil { glog.Warningf("Failed to delete namespace ns: %e", ns, err) } }(ns) glog.Infof("Created namespace %s", ns) // Create a service for these pods. glog.Infof("Creating service %s/serve-hostnames", ns) // Make several attempts to create a service. var svc *api.Service for start := time.Now(); time.Since(start) < serviceCreateTimeout; time.Sleep(2 * time.Second) { t := time.Now() svc, err = c.Services(ns).Create(&api.Service{ ObjectMeta: api.ObjectMeta{ Name: "serve-hostnames", Labels: map[string]string{ "name": "serve-hostname", }, }, Spec: api.ServiceSpec{ Ports: []api.ServicePort{{ Protocol: "TCP", Port: 9376, TargetPort: util.NewIntOrStringFromInt(9376), }}, Selector: map[string]string{ "name": "serve-hostname", }, }, }) glog.V(4).Infof("Service create %s/server-hostnames took %v", ns, time.Since(t)) if err == nil { break } glog.Warningf("After %v failed to create service %s/serve-hostnames: %v", time.Since(start), ns, err) } if err != nil { glog.Warningf("Unable to create service %s/%s: %v", ns, svc.Name, err) return } // Clean up service defer func() { glog.Infof("Cleaning up service %s/serve-hostnames", ns) // Make several attempts to delete the service. for start := time.Now(); time.Since(start) < deleteTimeout; time.Sleep(1 * time.Second) { if err := c.Services(ns).Delete(svc.Name); err == nil { return } glog.Warningf("After %v unable to delete service %s/%s: %v", time.Since(start), ns, svc.Name, err) } }() // Put serve-hostname pods on each node. podNames := []string{} for i, node := range nodes.Items { for j := 0; j < *podsPerNode; j++ { podName := fmt.Sprintf("serve-hostname-%d-%d", i, j) podNames = append(podNames, podName) // Make several attempts for start := time.Now(); time.Since(start) < podCreateTimeout; time.Sleep(2 * time.Second) { glog.Infof("Creating pod %s/%s on node %s", ns, podName, node.Name) t := time.Now() _, err = c.Pods(ns).Create(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: podName, Labels: map[string]string{ "name": "serve-hostname", }, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name: "serve-hostname", Image: "qingyuan/serve_hostname:1.1", Ports: []api.ContainerPort{{ContainerPort: 9376}}, }, }, NodeName: node.Name, }, }) glog.V(4).Infof("Pod create %s/%s request took %v", ns, podName, time.Since(t)) if err == nil { break } glog.Warningf("After %s failed to create pod %s/%s: %v", time.Since(start), ns, podName, err) } if err != nil { glog.Warningf("Failed to create pod %s/%s: %v", ns, podName, err) return } } } // Clean up the pods defer func() { glog.Info("Cleaning up pods") // Make several attempts to delete the pods. for _, podName := range podNames { for start := time.Now(); time.Since(start) < deleteTimeout; time.Sleep(1 * time.Second) { if err = c.Pods(ns).Delete(podName, nil); err == nil { break } glog.Warningf("After %v failed to delete pod %s/%s: %v", time.Since(start), ns, podName, err) } } }() glog.Info("Waiting for the serve-hostname pods to be ready") for _, podName := range podNames { var pod *api.Pod for start := time.Now(); time.Since(start) < podStartTimeout; time.Sleep(5 * time.Second) { pod, err = c.Pods(ns).Get(podName) if err != nil { glog.Warningf("Get pod %s/%s failed, ignoring for %v: %v", ns, podName, err, podStartTimeout) continue } if pod.Status.Phase == api.PodRunning { break } } if pod.Status.Phase != api.PodRunning { glog.Warningf("Gave up waiting on pod %s/%s to be running (saw %v)", ns, podName, pod.Status.Phase) } else { glog.Infof("%s/%s is running", ns, podName) } } // Wait for the endpoints to propagate. for start := time.Now(); time.Since(start) < endpointTimeout; time.Sleep(10 * time.Second) { _, err = http.Get(fmt.Sprintf("http://serve-hostnames.%s:9376", ns)) if err == nil { break } glog.Infof("After %v while making a request got error %v", time.Since(start), err) } if err != nil { glog.Errorf("Failed to get a response from service: %v", err) } // Repeatedly make requests. for iteration := 0; iteration != *upTo; iteration++ { responseChan := make(chan string, queries) // Use a channel of size *maxPar to throttle the number // of in-flight requests to avoid overloading the service. inFlight := make(chan struct{}, *maxPar) start := time.Now() for q := 0; q < queries; q++ { go func(i int, query int) { inFlight <- struct{}{} t := time.Now() resp, err := http.Get(fmt.Sprintf("http://serve-hostnames.%s:9376", ns)) glog.V(4).Infof("Call to serve-hostnames in namespace %s took %v", ns, time.Since(t)) if err != nil { glog.Warningf("Call failed during iteration %d query %d : %v", i, query, err) // If the query failed return a string which starts with a character // that can't be part of a hostname. responseChan <- fmt.Sprintf("!failed in iteration %d to issue query %d: %v", i, query, err) } else { defer resp.Body.Close() hostname, err := ioutil.ReadAll(resp.Body) if err != nil { responseChan <- fmt.Sprintf("!failed in iteration %d to read body of response: %v", i, err) } else { responseChan <- string(hostname) } } <-inFlight }(iteration, q) } responses := make(map[string]int, *podsPerNode*len(nodes.Items)) missing := 0 for q := 0; q < queries; q++ { r := <-responseChan glog.V(4).Infof("Got response from %s", r) responses[r]++ // If the returned hostname starts with '!' then it indicates // an error response. if len(r) > 0 && r[0] == '!' { glog.V(3).Infof("Got response %s", r) missing++ } } if missing > 0 { glog.Warningf("Missing %d responses out of %d", missing, queries) } // Report any nodes that did not respond. for n, node := range nodes.Items { for i := 0; i < *podsPerNode; i++ { name := fmt.Sprintf("serve-hostname-%d-%d", n, i) if _, ok := responses[name]; !ok { glog.Warningf("No response from pod %s on node %s at iteration %d", name, node.Name, iteration) } } } glog.Infof("Iteration %d took %v for %d queries (%.2f QPS) with %d missing", iteration, time.Since(start), queries-missing, float64(queries-missing)/time.Since(start).Seconds(), missing) } }
func proxyContext(version string) { f := NewFramework("proxy") prefix := "/api/" + version It("should proxy logs on node with explicit qinglet port", func() { node, err := pickNode(f.Client) Expect(err).NotTo(HaveOccurred()) // AbsPath preserves the trailing '/'. body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + ":10250/logs/").Do().Raw() if len(body) > 0 { if len(body) > 100 { body = body[:100] body = append(body, '.', '.', '.') } Logf("Got: %s", body) } Expect(err).NotTo(HaveOccurred()) }) It("should proxy logs on node", func() { node, err := pickNode(f.Client) Expect(err).NotTo(HaveOccurred()) body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + "/logs/").Do().Raw() if len(body) > 0 { if len(body) > 100 { body = body[:100] body = append(body, '.', '.', '.') } Logf("Got: %s", body) } Expect(err).NotTo(HaveOccurred()) }) It("should proxy to cadvisor", func() { node, err := pickNode(f.Client) Expect(err).NotTo(HaveOccurred()) body, err := f.Client.Get().AbsPath(prefix + "/proxy/nodes/" + node + ":4194/containers/").Do().Raw() if len(body) > 0 { if len(body) > 100 { body = body[:100] body = append(body, '.', '.', '.') } Logf("Got: %s", body) } Expect(err).NotTo(HaveOccurred()) }) It("should proxy through a service and a pod", func() { labels := map[string]string{"proxy-service-target": "true"} service, err := f.Client.Services(f.Namespace.Name).Create(&api.Service{ ObjectMeta: api.ObjectMeta{ GenerateName: "proxy-service-", }, Spec: api.ServiceSpec{ Selector: labels, Ports: []api.ServicePort{ { Name: "portname1", Port: 80, TargetPort: util.NewIntOrStringFromString("dest1"), }, { Name: "portname2", Port: 81, TargetPort: util.NewIntOrStringFromInt(162), }, }, }, }) Expect(err).NotTo(HaveOccurred()) defer func(name string) { err := f.Client.Services(f.Namespace.Name).Delete(name) if err != nil { Logf("Failed deleting service %v: %v", name, err) } }(service.Name) // Make an RC with a single pod. pods := []*api.Pod{} cfg := RCConfig{ Client: f.Client, Image: "qingyuan/porter:91d46193649807d1340b46797774d8b2", Name: service.Name, Namespace: f.Namespace.Name, Replicas: 1, PollInterval: time.Second, Env: map[string]string{ "SERVE_PORT_80": "not accessible via service", "SERVE_PORT_160": "foo", "SERVE_PORT_162": "bar", }, Ports: map[string]int{ "dest1": 160, "dest2": 162, }, Labels: labels, CreatedPods: &pods, } Expect(RunRC(cfg)).NotTo(HaveOccurred()) defer DeleteRC(f.Client, f.Namespace.Name, cfg.Name) Expect(f.WaitForAnEndpoint(service.Name)).NotTo(HaveOccurred()) // Try proxying through the service and directly to through the pod. svcPrefix := prefix + "/proxy/namespaces/" + f.Namespace.Name + "/services/" + service.Name podPrefix := prefix + "/proxy/namespaces/" + f.Namespace.Name + "/pods/" + pods[0].Name expectations := map[string]string{ svcPrefix + ":portname1": "foo", svcPrefix + ":portname2": "bar", podPrefix + ":80": "not accessible via service", podPrefix + ":160": "foo", podPrefix + ":162": "bar", // TODO: below entries don't work, but I believe we should make them work. // svcPrefix + ":80": "foo", // svcPrefix + ":81": "bar", // podPrefix + ":dest1": "foo", // podPrefix + ":dest2": "bar", } errors := []string{} for path, val := range expectations { body, err := f.Client.Get().AbsPath(path).Do().Raw() if err != nil { errors = append(errors, fmt.Sprintf("path %v gave error %v", path, err)) continue } if e, a := val, string(body); e != a { errors = append(errors, fmt.Sprintf("path %v: wanted %v, got %v", path, e, a)) } } if len(errors) != 0 { Fail(strings.Join(errors, "\n")) } }) }