func TestEtcdUpdateService(t *testing.T) { ctx := api.NewDefaultContext() fakeClient := tools.NewFakeEtcdClient(t) fakeClient.TestIndex = true registry, rest := NewTestEtcdRegistry(fakeClient) key, _ := rest.KeyFunc(ctx, "uniquefoo") key = etcdtest.AddPrefix(key) resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, makeTestService("uniquefoo")), 0) testService := api.Service{ ObjectMeta: api.ObjectMeta{ Name: "uniquefoo", ResourceVersion: strconv.FormatUint(resp.Node.ModifiedIndex, 10), Labels: map[string]string{ "baz": "bar", }, }, Spec: api.ServiceSpec{ Ports: []api.ServicePort{ {Name: "port", Protocol: api.ProtocolTCP, Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345)}, }, Selector: map[string]string{ "baz": "bar", }, SessionAffinity: "None", Type: api.ServiceTypeClusterIP, }, } _, err := registry.UpdateService(ctx, &testService) if err != nil { t.Errorf("unexpected error: %v", err) } svc, err := registry.GetService(ctx, "uniquefoo") if err != nil { t.Errorf("unexpected error: %v", err) } // Clear modified indices before the equality test. svc.ResourceVersion = "" testService.ResourceVersion = "" if !api.Semantic.DeepEqual(*svc, testService) { t.Errorf("Unexpected service: got\n %#v\n, wanted\n %#v", svc, testService) } }
func (s *ServiceController) ensureClusterService(cachedService *cachedService, clusterName string, service *api.Service, client *clientset.Clientset) error { var err error var needUpdate bool for i := 0; i < clientRetryCount; i++ { svc, err := client.Core().Services(service.Namespace).Get(service.Name) if err == nil { // service exists glog.V(5).Infof("Found service %s/%s from cluster %s", service.Namespace, service.Name, clusterName) //reserve immutable fields service.Spec.ClusterIP = svc.Spec.ClusterIP //reserve auto assigned field for i, oldPort := range svc.Spec.Ports { for _, port := range service.Spec.Ports { if port.NodePort == 0 { if !portEqualExcludeNodePort(&oldPort, &port) { svc.Spec.Ports[i] = port needUpdate = true } } else { if !portEqualForLB(&oldPort, &port) { svc.Spec.Ports[i] = port needUpdate = true } } } } if needUpdate { // we only apply spec update svc.Spec = service.Spec _, err = client.Core().Services(svc.Namespace).Update(svc) if err == nil { glog.V(5).Infof("Service %s/%s successfully updated to cluster %s", svc.Namespace, svc.Name, clusterName) return nil } else { glog.V(4).Infof("Failed to update %+v", err) } } else { glog.V(5).Infof("Service %s/%s is not updated to cluster %s as the spec are identical", svc.Namespace, svc.Name, clusterName) return nil } } else if errors.IsNotFound(err) { // Create service if it is not found glog.Infof("Service '%s/%s' is not found in cluster %s, trying to create new", service.Namespace, service.Name, clusterName) service.ResourceVersion = "" _, err = client.Core().Services(service.Namespace).Create(service) if err == nil { glog.V(5).Infof("Service %s/%s successfully created to cluster %s", service.Namespace, service.Name, clusterName) return nil } glog.V(4).Infof("Failed to create %+v", err) if errors.IsAlreadyExists(err) { glog.V(5).Infof("service %s/%s already exists in cluster %s", service.Namespace, service.Name, clusterName) return nil } } if errors.IsConflict(err) { glog.V(4).Infof("Not persisting update to service '%s/%s' that has been changed since we received it: %v", service.Namespace, service.Name, err) } // should we reuse same retry delay for all clusters? time.Sleep(cachedService.nextRetryDelay()) } return err }