func getTestService(identifier string, requestedPorts ...int32) v1.Service { ports := []v1.ServicePort{} for _, port := range requestedPorts { ports = append(ports, v1.ServicePort{ Name: fmt.Sprintf("port-%d", port), Protocol: v1.ProtocolTCP, Port: port, NodePort: getBackendPort(port), }) } svc := v1.Service{ Spec: v1.ServiceSpec{ Type: v1.ServiceTypeLoadBalancer, Ports: ports, }, } svc.Name = identifier svc.Namespace = "default" svc.UID = types.UID(identifier) return svc }
func (s *ServiceController) ensureClusterService(cachedService *cachedService, clusterName string, service *v1.Service, client *release_1_4.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 }
func TestHandlers(t *testing.T) { // There is a single service ns1/s1 in cluster mycluster. service := api_v1.Service{ ObjectMeta: api_v1.ObjectMeta{ Namespace: "ns1", Name: "s1", }, } service2 := api_v1.Service{ ObjectMeta: api_v1.ObjectMeta{ Namespace: "ns1", Name: "s1", Annotations: map[string]string{ "A": "B", }, }, } triggerChan := make(chan struct{}, 1) triggered := func() bool { select { case <-triggerChan: return true default: return false } } trigger := NewTriggerOnAllChangesPreproc( func(obj pkg_runtime.Object) { triggerChan <- struct{}{} }, func(obj pkg_runtime.Object) { SetClusterName(obj, "mycluster") }) trigger.OnAdd(&service) assert.True(t, triggered()) name, err := GetClusterName(&service) assert.NoError(t, err) assert.Equal(t, "mycluster", name) trigger.OnDelete(&service) assert.True(t, triggered()) trigger.OnUpdate(&service, &service) assert.False(t, triggered()) trigger.OnUpdate(&service, &service2) assert.True(t, triggered()) trigger2 := NewTriggerOnMetaAndSpecChangesPreproc( func(obj pkg_runtime.Object) { triggerChan <- struct{}{} }, func(obj pkg_runtime.Object) { SetClusterName(obj, "mycluster") }) service.Annotations = make(map[string]string) trigger2.OnAdd(&service) assert.True(t, triggered()) name, err = GetClusterName(&service) assert.NoError(t, err) assert.Equal(t, "mycluster", name) trigger2.OnDelete(&service) assert.True(t, triggered()) trigger2.OnUpdate(&service, &service) assert.False(t, triggered()) trigger2.OnUpdate(&service, &service2) assert.True(t, triggered()) service3 := api_v1.Service{ ObjectMeta: api_v1.ObjectMeta{ Namespace: "ns1", Name: "s1", }, Status: api_v1.ServiceStatus{ LoadBalancer: api_v1.LoadBalancerStatus{ Ingress: []api_v1.LoadBalancerIngress{{ Hostname: "A", }}, }, }, } trigger2.OnUpdate(&service, &service3) assert.False(t, triggered()) }
func TestGetLoadBalancerSourceRanges(t *testing.T) { checkError := func(v string) { annotations := make(map[string]string) annotations[AnnotationLoadBalancerSourceRangesKey] = v svc := v1.Service{} svc.Annotations = annotations _, err := GetLoadBalancerSourceRanges(&svc) if err == nil { t.Errorf("Expected error parsing: %q", v) } svc = v1.Service{} svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",") _, err = GetLoadBalancerSourceRanges(&svc) if err == nil { t.Errorf("Expected error parsing: %q", v) } } checkError("10.0.0.1/33") checkError("foo.bar") checkError("10.0.0.1/32,*") checkError("10.0.0.1/32,") checkError("10.0.0.1/32, ") checkError("10.0.0.1") checkOK := func(v string) netsets.IPNet { annotations := make(map[string]string) annotations[AnnotationLoadBalancerSourceRangesKey] = v svc := v1.Service{} svc.Annotations = annotations cidrs, err := GetLoadBalancerSourceRanges(&svc) if err != nil { t.Errorf("Unexpected error parsing: %q", v) } svc = v1.Service{} svc.Spec.LoadBalancerSourceRanges = strings.Split(v, ",") cidrs, err = GetLoadBalancerSourceRanges(&svc) if err != nil { t.Errorf("Unexpected error parsing: %q", v) } return cidrs } cidrs := checkOK("192.168.0.1/32") if len(cidrs) != 1 { t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice()) } cidrs = checkOK("192.168.0.1/32,192.168.0.1/32") if len(cidrs) != 1 { t.Errorf("Expected exactly one CIDR (after de-dup): %v", cidrs.StringSlice()) } cidrs = checkOK("192.168.0.1/32,192.168.0.2/32") if len(cidrs) != 2 { t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice()) } cidrs = checkOK(" 192.168.0.1/32 , 192.168.0.2/32 ") if len(cidrs) != 2 { t.Errorf("Expected two CIDRs: %v", cidrs.StringSlice()) } // check LoadBalancerSourceRanges not specified svc := v1.Service{} cidrs, err := GetLoadBalancerSourceRanges(&svc) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(cidrs) != 1 { t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice()) } if !IsAllowAll(cidrs) { t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice()) } // check SourceRanges annotation is empty annotations := make(map[string]string) annotations[AnnotationLoadBalancerSourceRangesKey] = "" svc = v1.Service{} svc.Annotations = annotations cidrs, err = GetLoadBalancerSourceRanges(&svc) if err != nil { t.Errorf("Unexpected error: %v", err) } if len(cidrs) != 1 { t.Errorf("Expected exactly one CIDR: %v", cidrs.StringSlice()) } if !IsAllowAll(cidrs) { t.Errorf("Expected default to be allow-all: %v", cidrs.StringSlice()) } }