Merge pull request #11077 from krousey/service_flake

Adding retry logic around service updates
This commit is contained in:
Tim Hockin 2015-07-13 13:06:02 -07:00
commit 3452748de9

View File

@ -26,6 +26,7 @@ import (
"time" "time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels" "github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@ -370,8 +371,9 @@ var _ = Describe("Services", func() {
t.CreateWebserverRC(1) t.CreateWebserverRC(1)
By("changing service " + serviceName + " to type=NodePort") By("changing service " + serviceName + " to type=NodePort")
service.Spec.Type = api.ServiceTypeNodePort service, err = updateService(c, ns, serviceName, func(s *api.Service) {
service, err = c.Services(ns).Update(service) s.Spec.Type = api.ServiceTypeNodePort
})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if service.Spec.Type != api.ServiceTypeNodePort { if service.Spec.Type != api.ServiceTypeNodePort {
@ -398,7 +400,9 @@ var _ = Describe("Services", func() {
By("changing service " + serviceName + " to type=LoadBalancer") By("changing service " + serviceName + " to type=LoadBalancer")
service.Spec.Type = api.ServiceTypeLoadBalancer service.Spec.Type = api.ServiceTypeLoadBalancer
service, err = c.Services(ns).Update(service) service, err = updateService(c, ns, serviceName, func(s *api.Service) {
s.Spec.Type = api.ServiceTypeLoadBalancer
})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
// Wait for the load balancer to be created asynchronously // Wait for the load balancer to be created asynchronously
@ -434,8 +438,9 @@ var _ = Describe("Services", func() {
//Check for (unlikely) assignment at bottom of range //Check for (unlikely) assignment at bottom of range
nodePort2 = nodePort1 + 1 nodePort2 = nodePort1 + 1
} }
service.Spec.Ports[0].NodePort = nodePort2 service, err = updateService(c, ns, serviceName, func(s *api.Service) {
service, err = c.Services(ns).Update(service) s.Spec.Ports[0].NodePort = nodePort2
})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if service.Spec.Type != api.ServiceTypeLoadBalancer { if service.Spec.Type != api.ServiceTypeLoadBalancer {
@ -463,9 +468,10 @@ var _ = Describe("Services", func() {
testNotReachable(ip, nodePort1) testNotReachable(ip, nodePort1)
By("changing service " + serviceName + " back to type=ClusterIP") By("changing service " + serviceName + " back to type=ClusterIP")
service.Spec.Type = api.ServiceTypeClusterIP service, err = updateService(c, ns, serviceName, func(s *api.Service) {
service.Spec.Ports[0].NodePort = 0 s.Spec.Type = api.ServiceTypeClusterIP
service, err = c.Services(ns).Update(service) s.Spec.Ports[0].NodePort = 0
})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if service.Spec.Type != api.ServiceTypeClusterIP { if service.Spec.Type != api.ServiceTypeClusterIP {
@ -552,8 +558,9 @@ var _ = Describe("Services", func() {
testLoadBalancerReachable(ingress, 80) testLoadBalancerReachable(ingress, 80)
By("changing service " + serviceName + " to type=NodePort") By("changing service " + serviceName + " to type=NodePort")
service.Spec.Type = api.ServiceTypeNodePort service, err = updateService(c, ns, serviceName, func(s *api.Service) {
service, err = c.Services(ns).Update(service) s.Spec.Type = api.ServiceTypeNodePort
})
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
if service.Spec.Type != api.ServiceTypeNodePort { if service.Spec.Type != api.ServiceTypeNodePort {
@ -678,8 +685,9 @@ var _ = Describe("Services", func() {
} }
} }
By(fmt.Sprintf("changing service "+serviceName+" to out-of-range NodePort %d", outOfRangeNodePort)) By(fmt.Sprintf("changing service "+serviceName+" to out-of-range NodePort %d", outOfRangeNodePort))
service.Spec.Ports[0].NodePort = outOfRangeNodePort result, err := updateService(c, ns, serviceName, func(s *api.Service) {
result, err := t.Client.Services(t.Namespace).Update(service) s.Spec.Ports[0].NodePort = outOfRangeNodePort
})
if err == nil { if err == nil {
Failf("failed to prevent update of service with out-of-range NodePort: %v", result) Failf("failed to prevent update of service with out-of-range NodePort: %v", result)
} }
@ -801,6 +809,29 @@ var _ = Describe("Services", func() {
}) })
}) })
// updateService fetches a service, calls the update function on it,
// and then attempts to send the updated service. It retries up to 2
// times in the face of timeouts and conflicts.
func updateService(c *client.Client, namespace, serviceName string, update func(*api.Service)) (*api.Service, error) {
var service *api.Service
var err error
for i := 0; i < 3; i++ {
service, err = c.Services(namespace).Get(serviceName)
if err != nil {
return service, err
}
update(service)
service, err = c.Services(namespace).Update(service)
if !errors.IsConflict(err) && !errors.IsServerTimeout(err) {
return service, err
}
}
return service, err
}
func waitForLoadBalancerIngress(c *client.Client, serviceName, namespace string) (*api.Service, error) { func waitForLoadBalancerIngress(c *client.Client, serviceName, namespace string) (*api.Service, error) {
// TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable // TODO: once support ticket 21807001 is resolved, reduce this timeout back to something reasonable
const timeout = 20 * time.Minute const timeout = 20 * time.Minute