Code change:
Follow up from
Bumping this up to P1 given that 0.12.2 wasn't able to create a service with an external load balancer and we didn't notice before cutting the release.
No, to be clearer, 0.12.2 wasn't able to create a service with ELB on GKE. That was on our side entirely.
But it doesn't invalidate the need for this.
The example is using ELB.
are you actively working on this? If not, I'd be up for doing it today.
Maybe not actively but I know what to, however I won't be able to finish it today, so if you think you can do it today please move forward.
We run the e2e tests on GKE, so if we had a test for creating an ELB we would have known that the 0.12.2 release wouldn't work on GKE. I don't see how your point applies. The e2e tests are in place so that we don't have to test each feature manually to verify that it is working, and we only found out that this feature was broken on GKE after we pushed 0.12.2, hence the need for an e2e test.
I think and you are in fact in agreement
right now, k8petstore tests the external load balancer by curling down the amount of transactions ingested from the REST API. im playing with porting it as a e2e test now. The code in the shell script is a little raw, but you can see that it specifies a PUBLIC_IP and then curls down from it at the end ().
that sounds great. What I'd really like to see here though (and what is going to do early next week) is a very simple test that isolates creating a service with an ELB to verify that creating a load balancer works in isolation from a complex test of other parts of the system. This will give us a really clear signal when the test starts to fail instead of needing to debug lots of moving parts when we see a test failure.

Related discussion:
text: }() }, 240.0) <ins> It("should be able to create a functioning external load balancer", func() { serviceName := "external-lb-test" ns := api.NamespaceDefault labels := map[string]string{ "key0": "value0", } service := &api.Service{ ObjectMeta: api.ObjectMeta{ Name: serviceName, }, Spec: api.ServiceSpec{ Port:                       80, Selector:                   labels, TargetPort:                 util.NewIntOrStringFromInt(80), CreateExternalLoadBalancer: true, }, } By("cleaning up previous service " + serviceName + " from namespace " + ns) c.Services(ns).Delete(serviceName) By("creating service " + serviceName + " with external load balancer in namespace " + ns) result, err := c.Services(ns).Create(service) Expect(err).NotTo(HaveOccurred()) defer func(ns, serviceName string) { // clean up when we're done By("deleting service " + serviceName + " in namespace " + ns) err := c.Services(ns).Delete(serviceName) Expect(err).NotTo(HaveOccurred()) }(ns, serviceName) if len(result.Spec.PublicIPs) != 1 { Failf("got unexpected number (%d) of public IPs for externally load balanced service: %v", result.Spec.PublicIPs, result) } ip := result.Spec.PublicIPs[0] port := result.Spec.Port pod := &api.Pod{ TypeMeta: api.TypeMeta{ Kind:       "Pod", APIVersion: "v1beta1", }, ObjectMeta: api.ObjectMeta{ Name:   "elb-test-" + string(util.NewUUID()), Labels: labels, }, Spec: api.PodSpec{ Containers: []api.Container{ { Name:  "webserver", Image: "kubernetes/test-webserver", }, }, }, } By("creating pod to be part of service " + serviceName) podClient := c.Pods(api.NamespaceDefault) defer func() { By("deleting pod " + pod.Name) defer GinkgoRecover() podClient.Delete(pod.Name) }() if _, err := podClient.Create(pod); err != nil { Failf("Failed to create pod %s: %v", pod.Name, err) } expectNoError(waitForPodRunning(c, pod.Name)) By("hitting the pod through the service's external load balancer") var resp *http.Response for t := time.Now(); time.Since(t) < 4*time.Minute; time.Sleep(5 * time.Second) { resp, err = http.Get(fmt.Sprintf("http://%s:%d", ip, port)) if err == nil { break } } Expect(err).NotTo(HaveOccurred()) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) Expect(err).NotTo(HaveOccurred()) if resp.StatusCode != 200 { Failf("received non-success return status %q trying to access pod through load balancer; got body: %s", resp.Status, string(body)) } if !strings.Contains(string(body), "test-webserver") { Failf("received response body without expected substring 'test-webserver': %s", string(body)) } }) </ins> It("should correctly serve identically named services in different namespaces on different external IP addresses", func() { serviceNames := []string{"services-namespace-test0"} // Could add more here, but then it takes longer. namespaces := []string{"namespace0", "namespace1"}   // As above.