// Run launches an F5 route sync process using the provided options. It never exits. func (o *F5RouterOptions) Run() error { cfg := f5plugin.F5PluginConfig{ Host: o.Host, Username: o.Username, Password: o.Password, HttpVserver: o.HttpVserver, HttpsVserver: o.HttpsVserver, PrivateKey: o.PrivateKey, Insecure: o.Insecure, PartitionPath: o.PartitionPath, } f5Plugin, err := f5plugin.NewF5Plugin(cfg) if err != nil { return err } oc, kc, err := o.Config.Clients() if err != nil { return err } statusPlugin := controller.NewStatusAdmitter(f5Plugin, oc, o.RouterName) plugin := controller.NewUniqueHost(statusPlugin, o.RouteSelectionFunc(), statusPlugin) factory := o.RouterSelection.NewFactory(oc, kc) controller := factory.Create(plugin) controller.Run() select {} }
// Run launches a template router using the provided options. It never exits. func (o *TemplateRouterOptions) Run() error { pluginCfg := templateplugin.TemplatePluginConfig{ WorkingDir: o.WorkingDir, TemplatePath: o.TemplateFile, ReloadScriptPath: o.ReloadScript, DefaultCertificate: o.DefaultCertificate, StatsPort: o.StatsPort, StatsUsername: o.StatsUsername, StatsPassword: o.StatsPassword, PeerService: o.RouterService, IncludeUDP: o.RouterSelection.IncludeUDP, } templatePlugin, err := templateplugin.NewTemplatePlugin(pluginCfg) if err != nil { return err } plugin := controller.NewUniqueHost(templatePlugin, controller.HostForRoute) oc, kc, err := o.Config.Clients() if err != nil { return err } factory := o.RouterSelection.NewFactory(oc, kc) controller := factory.Create(plugin) controller.Run() proc.StartReaper() select {} }
func TestNamespaceScopingFromEmpty(t *testing.T) { router := newTestRouter(make(map[string]ServiceAliasConfig)) templatePlugin := newDefaultTemplatePlugin(router, true) // TODO: move tests that rely on unique hosts to pkg/router/controller and remove them from // here plugin := controller.NewUniqueHost(templatePlugin, controller.HostForRoute, controller.LogRejections) // no namespaces allowed plugin.HandleNamespaces(sets.String{}) //add route := &routeapi.Route{ ObjectMeta: kapi.ObjectMeta{Namespace: "foo", Name: "test"}, Spec: routeapi.RouteSpec{ Host: "www.example.com", To: routeapi.RouteTargetReference{ Name: "TestService", Weight: new(int32), }, }, } // ignores all events for namespace that doesn't match for _, s := range []watch.EventType{watch.Added, watch.Modified, watch.Deleted} { plugin.HandleRoute(s, route) if _, ok := router.FindServiceUnit("foo/TestService"); ok || plugin.HostLen() != 0 { t.Errorf("unexpected router state %#v", router) } } // allow non matching plugin.HandleNamespaces(sets.NewString("bar")) for _, s := range []watch.EventType{watch.Added, watch.Modified, watch.Deleted} { plugin.HandleRoute(s, route) if _, ok := router.FindServiceUnit("foo/TestService"); ok || plugin.HostLen() != 0 { t.Errorf("unexpected router state %#v", router) } } // allow foo plugin.HandleNamespaces(sets.NewString("foo", "bar")) plugin.HandleRoute(watch.Added, route) if _, ok := router.FindServiceUnit("foo/TestService"); !ok || plugin.HostLen() != 1 { t.Errorf("unexpected router state %#v", router) } // forbid foo, and make sure it's cleared plugin.HandleNamespaces(sets.NewString("bar")) if _, ok := router.FindServiceUnit("foo/TestService"); ok || plugin.HostLen() != 0 { t.Errorf("unexpected router state %#v", router) } plugin.HandleRoute(watch.Modified, route) if _, ok := router.FindServiceUnit("foo/TestService"); ok || plugin.HostLen() != 0 { t.Errorf("unexpected router state %#v", router) } plugin.HandleRoute(watch.Added, route) if _, ok := router.FindServiceUnit("foo/TestService"); ok || plugin.HostLen() != 0 { t.Errorf("unexpected router state %#v", router) } }
// Run launches an F5 route sync process using the provided options. It never exits. func (o *F5RouterOptions) Run() error { cfg := f5plugin.F5PluginConfig{ Host: o.Host, Username: o.Username, Password: o.Password, HttpVserver: o.HttpVserver, HttpsVserver: o.HttpsVserver, PrivateKey: o.PrivateKey, Insecure: o.Insecure, } f5Plugin, err := f5plugin.NewF5Plugin(cfg) if err != nil { return err } plugin := controller.NewUniqueHost(f5Plugin, controller.HostForRoute) oc, kc, err := o.Config.Clients() if err != nil { return err } factory := o.RouterSelection.NewFactory(oc, kc) controller := factory.Create(plugin) controller.Run() select {} }
// Run launches an F5 route sync process using the provided options. It never exits. func (o *F5RouterOptions) Run() error { cfg := f5plugin.F5PluginConfig{ Host: o.Host, Username: o.Username, Password: o.Password, HttpVserver: o.HttpVserver, HttpsVserver: o.HttpsVserver, PrivateKey: o.PrivateKey, Insecure: o.Insecure, PartitionPath: o.PartitionPath, InternalAddress: o.InternalAddress, VxlanGateway: o.VxlanGateway, } f5Plugin, err := f5plugin.NewF5Plugin(cfg) if err != nil { return err } oc, _, kc, err := o.Config.Clients() if err != nil { return err } statusPlugin := controller.NewStatusAdmitter(f5Plugin, oc, o.RouterName) uniqueHostPlugin := controller.NewUniqueHost(statusPlugin, o.RouteSelectionFunc(), statusPlugin) plugin := controller.NewHostAdmitter(uniqueHostPlugin, o.F5RouteAdmitterFunc(), false, statusPlugin) factory := o.RouterSelection.NewFactory(oc, kc) watchNodes := (len(o.InternalAddress) != 0 && len(o.VxlanGateway) != 0) controller := factory.Create(plugin, watchNodes) controller.Run() select {} }
// launchRouter launches a template router that communicates with the // api via the provided clients. func launchRouter(oc osclient.Interface, kc kclient.Interface, maxDelay int32, name string, reloadInterval int, reloadCounts map[string]int) (templatePlugin *templateplugin.TemplatePlugin) { r := templateplugin.NewFakeTemplateRouter() reloadCounts[name] = 0 r.EnableRateLimiter(reloadInterval, func() error { reloadCounts[name]++ return nil }) templatePlugin = &templateplugin.TemplatePlugin{Router: r} statusPlugin := controller.NewStatusAdmitter(templatePlugin, oc, name) validationPlugin := controller.NewExtendedValidator(statusPlugin, controller.RejectionRecorder(statusPlugin)) uniquePlugin := controller.NewUniqueHost(validationPlugin, controller.HostForRoute, controller.RejectionRecorder(statusPlugin)) var plugin router.Plugin = uniquePlugin if maxDelay > 0 { plugin = NewDelayPlugin(plugin, maxDelay) } factory := controllerfactory.NewDefaultRouterControllerFactory(oc, kc) controller := factory.Create(plugin) controller.Run() return }
// Run launches a template router using the provided options. It never exits. func (o *TemplateRouterOptions) Run() error { pluginCfg := templateplugin.TemplatePluginConfig{ WorkingDir: o.WorkingDir, TemplatePath: o.TemplateFile, ReloadScriptPath: o.ReloadScript, ReloadInterval: o.ReloadInterval, DefaultCertificate: o.DefaultCertificate, DefaultCertificatePath: o.DefaultCertificatePath, DefaultCertificateDir: o.DefaultCertificateDir, StatsPort: o.StatsPort, StatsUsername: o.StatsUsername, StatsPassword: o.StatsPassword, PeerService: o.RouterService, BindPortsAfterSync: o.BindPortsAfterSync, IncludeUDP: o.RouterSelection.IncludeUDP, AllowWildcardRoutes: o.RouterSelection.AllowWildcardRoutes, } oc, kc, err := o.Config.Clients() if err != nil { return err } svcFetcher := templateplugin.NewListWatchServiceLookup(kc.Core(), 10*time.Minute) templatePlugin, err := templateplugin.NewTemplatePlugin(pluginCfg, svcFetcher) if err != nil { return err } statusPlugin := controller.NewStatusAdmitter(templatePlugin, oc, o.RouterName) var nextPlugin router.Plugin = statusPlugin if o.ExtendedValidation { nextPlugin = controller.NewExtendedValidator(nextPlugin, controller.RejectionRecorder(statusPlugin)) } uniqueHostPlugin := controller.NewUniqueHost(nextPlugin, o.RouteSelectionFunc(), controller.RejectionRecorder(statusPlugin)) plugin := controller.NewHostAdmitter(uniqueHostPlugin, o.RouteAdmissionFunc(), o.RestrictSubdomainOwnership, controller.RejectionRecorder(statusPlugin)) factory := o.RouterSelection.NewFactory(oc, kc) controller := factory.Create(plugin, false) controller.Run() proc.StartReaper() select {} }
// Run launches a template router using the provided options. It never exits. func (o *TemplateRouterOptions) Run() error { pluginCfg := templateplugin.TemplatePluginConfig{ WorkingDir: o.WorkingDir, TemplatePath: o.TemplateFile, ReloadScriptPath: o.ReloadScript, ReloadInterval: o.ReloadInterval, DefaultCertificate: o.DefaultCertificate, DefaultCertificatePath: o.DefaultCertificatePath, StatsPort: o.StatsPort, StatsUsername: o.StatsUsername, StatsPassword: o.StatsPassword, PeerService: o.RouterService, IncludeUDP: o.RouterSelection.IncludeUDP, } templatePlugin, err := templateplugin.NewTemplatePlugin(pluginCfg) if err != nil { return err } oc, kc, err := o.Config.Clients() if err != nil { return err } statusPlugin := controller.NewStatusAdmitter(templatePlugin, oc, o.RouterName) var nextPlugin router.Plugin = statusPlugin if o.ExtendedValidation { nextPlugin = controller.NewExtendedValidator(nextPlugin, controller.RejectionRecorder(statusPlugin)) } plugin := controller.NewUniqueHost(nextPlugin, o.RouteSelectionFunc(), controller.RejectionRecorder(statusPlugin)) factory := o.RouterSelection.NewFactory(oc, kc) controller := factory.Create(plugin) controller.Run() proc.StartReaper() select {} }
// TestHandleRouteExtendedValidation test route watch events with extended route configuration validation. func TestHandleRouteExtendedValidation(t *testing.T) { rejections := &fakeRejections{} router := newTestRouter(make(map[string]ServiceUnit)) templatePlugin := newDefaultTemplatePlugin(router, true) // TODO: move tests that rely on unique hosts to pkg/router/controller and remove them from // here extendedValidatorPlugin := controller.NewExtendedValidator(templatePlugin, rejections) plugin := controller.NewUniqueHost(extendedValidatorPlugin, controller.HostForRoute, rejections) original := unversioned.Time{Time: time.Now()} //add route := &routeapi.Route{ ObjectMeta: kapi.ObjectMeta{ CreationTimestamp: original, Namespace: "foo", Name: "test", }, Spec: routeapi.RouteSpec{ Host: "www.example.com", To: kapi.ObjectReference{ Name: "TestService", }, }, } serviceUnitKey := fmt.Sprintf("%s/%s", route.Namespace, route.Spec.To.Name) plugin.HandleRoute(watch.Added, route) if !router.Committed { t.Errorf("Expected router to be committed after HandleRoute call") } actualSU, ok := router.FindServiceUnit(serviceUnitKey) if !ok { t.Errorf("TestHandleRoute was unable to find the service unit %s after HandleRoute was called", route.Spec.To.Name) } else { serviceAliasCfg, ok := actualSU.ServiceAliasConfigs[router.routeKey(route)] if !ok { t.Errorf("TestHandleRoute expected route key %s", router.routeKey(route)) } else { if serviceAliasCfg.Host != route.Spec.Host || serviceAliasCfg.Path != route.Spec.Path { t.Errorf("Expected route did not match service alias config %v : %v", route, serviceAliasCfg) } } } if len(rejections.rejections) > 0 { t.Fatalf("did not expect a recorded rejection: %#v", rejections) } tests := []struct { name string route *routeapi.Route errorExpected bool }{ { name: "No TLS Termination", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.no.tls.test", TLS: &routeapi.TLSConfig{ Termination: "", }, }, }, errorExpected: true, }, { name: "Passthrough termination OK", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.passthrough.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationPassthrough, }, }, }, errorExpected: false, }, { name: "Reencrypt termination OK with certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.example.com", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, Certificate: testCertificate, Key: testPrivateKey, CACertificate: testCACertificate, DestinationCACertificate: testDestinationCACertificate, }, }, }, errorExpected: false, }, { name: "Reencrypt termination OK with bad config", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.reencypt.badconfig.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, Certificate: "def", Key: "ghi", CACertificate: "jkl", DestinationCACertificate: "abc", }, }, }, errorExpected: true, }, { name: "Reencrypt termination OK without certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.reencypt.nocerts.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, DestinationCACertificate: testDestinationCACertificate, }, }, }, errorExpected: false, }, { name: "Reencrypt termination bad config without certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.reencypt.badconfignocerts.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, DestinationCACertificate: "abc", }, }, }, errorExpected: true, }, { name: "Reencrypt termination no dest cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.reencypt.nodestcert.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, Certificate: testCertificate, Key: testPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: true, }, { name: "Edge termination OK with certs without host", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: testCertificate, Key: testPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: false, }, { name: "Edge termination OK with certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.example.com", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: testCertificate, Key: testPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: false, }, { name: "Edge termination bad config with certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.badconfig.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: "abc", Key: "abc", CACertificate: "abc", }, }, }, errorExpected: true, }, { name: "Edge termination mismatched key and cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.mismatchdkeyandcert.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: testCertificate, Key: testExpiredCertPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: true, }, { name: "Edge termination expired cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.expiredcert.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: testExpiredCAUnknownCertificate, Key: testExpiredCertPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: true, }, { name: "Edge termination expired cert key mismatch", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.expiredcertkeymismatch.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, Certificate: testExpiredCAUnknownCertificate, Key: testPrivateKey, CACertificate: testCACertificate, }, }, }, errorExpected: true, }, { name: "Edge termination OK without certs", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.nocerts.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, }, }, }, errorExpected: false, }, { name: "Edge termination, bad dest cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.edge.baddestcert.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationEdge, DestinationCACertificate: "abc", }, }, }, errorExpected: true, }, { name: "Passthrough termination, bad cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.passthrough.badcert.test", TLS: &routeapi.TLSConfig{Termination: routeapi.TLSTerminationPassthrough, Certificate: "test"}, }, }, errorExpected: true, }, { name: "Passthrough termination, bad key", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.passthrough.badkey.test", TLS: &routeapi.TLSConfig{Termination: routeapi.TLSTerminationPassthrough, Key: "test"}, }, }, errorExpected: true, }, { name: "Passthrough termination, bad ca cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.passthrough.badcacert.test", TLS: &routeapi.TLSConfig{Termination: routeapi.TLSTerminationPassthrough, CACertificate: "test"}, }, }, errorExpected: true, }, { name: "Passthrough termination, bad dest ca cert", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.passthrough.baddestcacert.test", TLS: &routeapi.TLSConfig{Termination: routeapi.TLSTerminationPassthrough, DestinationCACertificate: "test"}, }, }, errorExpected: true, }, { name: "Invalid termination type", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ TLS: &routeapi.TLSConfig{ Termination: "invalid", }, }, }, errorExpected: false, }, { name: "Double escaped newlines", route: &routeapi.Route{ Spec: routeapi.RouteSpec{ Host: "www.reencrypt.doubleescapednewlines.test", TLS: &routeapi.TLSConfig{ Termination: routeapi.TLSTerminationReencrypt, Certificate: "d\\nef", Key: "g\\nhi", CACertificate: "j\\nkl", DestinationCACertificate: "j\\nkl", }, }, }, errorExpected: true, }, } for _, tc := range tests { err := plugin.HandleRoute(watch.Added, tc.route) if tc.errorExpected { if err == nil { t.Fatalf("test case %s: expected an error, got none", tc.name) } } else { if err != nil { t.Fatalf("test case %s: expected no errors, got %v", tc.name, err) } } } }
// TestHandleRoute test route watch events func TestHandleRoute(t *testing.T) { rejections := &fakeRejections{} router := newTestRouter(make(map[string]ServiceUnit)) templatePlugin := newDefaultTemplatePlugin(router, true) // TODO: move tests that rely on unique hosts to pkg/router/controller and remove them from // here plugin := controller.NewUniqueHost(templatePlugin, controller.HostForRoute, rejections) original := unversioned.Time{Time: time.Now()} //add route := &routeapi.Route{ ObjectMeta: kapi.ObjectMeta{ CreationTimestamp: original, Namespace: "foo", Name: "test", }, Spec: routeapi.RouteSpec{ Host: "www.example.com", To: kapi.ObjectReference{ Name: "TestService", }, }, } serviceUnitKey := fmt.Sprintf("%s/%s", route.Namespace, route.Spec.To.Name) plugin.HandleRoute(watch.Added, route) if !router.Committed { t.Errorf("Expected router to be committed after HandleRoute call") } actualSU, ok := router.FindServiceUnit(serviceUnitKey) if !ok { t.Errorf("TestHandleRoute was unable to find the service unit %s after HandleRoute was called", route.Spec.To.Name) } else { serviceAliasCfg, ok := actualSU.ServiceAliasConfigs[router.routeKey(route)] if !ok { t.Errorf("TestHandleRoute expected route key %s", router.routeKey(route)) } else { if serviceAliasCfg.Host != route.Spec.Host || serviceAliasCfg.Path != route.Spec.Path { t.Errorf("Expected route did not match service alias config %v : %v", route, serviceAliasCfg) } } } if len(rejections.rejections) > 0 { t.Fatalf("did not expect a recorded rejection: %#v", rejections) } // attempt to add a second route with a newer time, verify it is ignored duplicateRoute := &routeapi.Route{ ObjectMeta: kapi.ObjectMeta{ CreationTimestamp: unversioned.Time{Time: original.Add(time.Hour)}, Namespace: "foo", Name: "dupe", }, Spec: routeapi.RouteSpec{ Host: "www.example.com", To: kapi.ObjectReference{ Name: "TestService2", }, }, } if err := plugin.HandleRoute(watch.Added, duplicateRoute); err == nil { t.Fatal("unexpected non-error") } if _, ok := router.FindServiceUnit("foo/TestService2"); ok { t.Fatalf("unexpected second unit: %#v", router) } if r, ok := plugin.RoutesForHost("www.example.com"); !ok || r[0].Name != "test" { t.Fatalf("unexpected claimed routes: %#v", r) } if len(rejections.rejections) != 1 || rejections.rejections[0].route.Name != "dupe" || rejections.rejections[0].reason != "HostAlreadyClaimed" || rejections.rejections[0].message != "route test already exposes www.example.com and is older" { t.Fatalf("did not record rejection: %#v", rejections) } rejections.rejections = nil // attempt to remove the second route that is not being used, verify it is ignored if err := plugin.HandleRoute(watch.Deleted, duplicateRoute); err == nil { t.Fatal("unexpected non-error") } if _, ok := router.FindServiceUnit("foo/TestService2"); ok { t.Fatalf("unexpected second unit: %#v", router) } if _, ok := router.FindServiceUnit("foo/TestService"); !ok { t.Fatalf("unexpected first unit: %#v", router) } if r, ok := plugin.RoutesForHost("www.example.com"); !ok || r[0].Name != "test" { t.Fatalf("unexpected claimed routes: %#v", r) } if len(rejections.rejections) != 1 || rejections.rejections[0].route.Name != "dupe" || rejections.rejections[0].reason != "HostAlreadyClaimed" || rejections.rejections[0].message != "route test already exposes www.example.com and is older" { t.Fatalf("did not record rejection: %#v", rejections) } rejections.rejections = nil // add a second route with an older time, verify it takes effect duplicateRoute.CreationTimestamp = unversioned.Time{Time: original.Add(-time.Hour)} if err := plugin.HandleRoute(watch.Added, duplicateRoute); err != nil { t.Fatal("unexpected error") } otherSU, ok := router.FindServiceUnit("foo/TestService2") if !ok { t.Fatalf("missing second unit: %#v", router) } if len(actualSU.ServiceAliasConfigs) != 0 || len(otherSU.ServiceAliasConfigs) != 1 { t.Errorf("incorrect router state: %#v", router) } if _, ok := actualSU.ServiceAliasConfigs[router.routeKey(route)]; ok { t.Errorf("unexpected service alias config %s", router.routeKey(route)) } if len(rejections.rejections) != 1 || rejections.rejections[0].route.Name != "test" || rejections.rejections[0].reason != "HostAlreadyClaimed" || rejections.rejections[0].message != "replaced by older route dupe" { t.Fatalf("did not record rejection: %#v", rejections) } rejections.rejections = nil //mod route.Spec.Host = "www.example2.com" if err := plugin.HandleRoute(watch.Modified, route); err != nil { t.Fatal("unexpected error") } if !router.Committed { t.Errorf("Expected router to be committed after HandleRoute call") } actualSU, ok = router.FindServiceUnit(serviceUnitKey) if !ok { t.Errorf("TestHandleRoute was unable to find the service unit %s after HandleRoute was called", route.Spec.To.Name) } else { serviceAliasCfg, ok := actualSU.ServiceAliasConfigs[router.routeKey(route)] if !ok { t.Errorf("TestHandleRoute expected route key %s", router.routeKey(route)) } else { if serviceAliasCfg.Host != route.Spec.Host || serviceAliasCfg.Path != route.Spec.Path { t.Errorf("Expected route did not match service alias config %v : %v", route, serviceAliasCfg) } } } if plugin.HostLen() != 1 { t.Fatalf("did not clear claimed route: %#v", plugin) } if len(rejections.rejections) != 0 { t.Fatalf("unexpected rejection: %#v", rejections) } //delete if err := plugin.HandleRoute(watch.Deleted, route); err != nil { t.Fatal("unexpected error") } if !router.Committed { t.Errorf("Expected router to be committed after HandleRoute call") } actualSU, ok = router.FindServiceUnit(serviceUnitKey) if !ok { t.Errorf("TestHandleRoute was unable to find the service unit %s after HandleRoute was called", route.Spec.To.Name) } else { _, ok := actualSU.ServiceAliasConfigs[router.routeKey(route)] if ok { t.Errorf("TestHandleRoute did not expect route key %s", router.routeKey(route)) } } if plugin.HostLen() != 0 { t.Errorf("did not clear claimed route: %#v", plugin) } if len(rejections.rejections) != 0 { t.Fatalf("unexpected rejection: %#v", rejections) } }
// TestHandleCPEndpoints test endpoint watch events with UDP excluded func TestHandleTCPEndpoints(t *testing.T) { testCases := []struct { name string //human readable name for test case eventType watch.EventType //type to be passed to the HandleEndpoints method endpoints *kapi.Endpoints //endpoints to be passed to the HandleEndpoints method expectedServiceUnit *ServiceUnit //service unit that will be compared against. }{ { name: "Endpoint add", eventType: watch.Added, endpoints: &kapi.Endpoints{ ObjectMeta: kapi.ObjectMeta{ Namespace: "foo", Name: "test", //kapi.endpoints inherits the name of the service }, Subsets: []kapi.EndpointSubset{{ Addresses: []kapi.EndpointAddress{{IP: "1.1.1.1"}}, Ports: []kapi.EndpointPort{ {Port: 345}, {Port: 346, Protocol: kapi.ProtocolUDP}, }, }}, //not specifying a port to force the port 80 assumption }, expectedServiceUnit: &ServiceUnit{ Name: "foo/test", //service name from kapi.endpoints object EndpointTable: []Endpoint{ { ID: "1.1.1.1:345", IP: "1.1.1.1", Port: "345", }, }, }, }, { name: "Endpoint mod", eventType: watch.Modified, endpoints: &kapi.Endpoints{ ObjectMeta: kapi.ObjectMeta{ Namespace: "foo", Name: "test", }, Subsets: []kapi.EndpointSubset{{ Addresses: []kapi.EndpointAddress{{IP: "2.2.2.2"}}, Ports: []kapi.EndpointPort{ {Port: 8080}, {Port: 8081, Protocol: kapi.ProtocolUDP}, }, }}, }, expectedServiceUnit: &ServiceUnit{ Name: "foo/test", EndpointTable: []Endpoint{ { ID: "2.2.2.2:8080", IP: "2.2.2.2", Port: "8080", }, }, }, }, { name: "Endpoint delete", eventType: watch.Deleted, endpoints: &kapi.Endpoints{ ObjectMeta: kapi.ObjectMeta{ Namespace: "foo", Name: "test", }, Subsets: []kapi.EndpointSubset{{ Addresses: []kapi.EndpointAddress{{IP: "3.3.3.3"}}, Ports: []kapi.EndpointPort{{Port: 0}}, }}, }, expectedServiceUnit: &ServiceUnit{ Name: "foo/test", EndpointTable: []Endpoint{}, }, }, } router := newTestRouter(make(map[string]ServiceUnit)) templatePlugin := newDefaultTemplatePlugin(router, false) // TODO: move tests that rely on unique hosts to pkg/router/controller and remove them from // here plugin := controller.NewUniqueHost(templatePlugin, controller.HostForRoute, controller.LogRejections) for _, tc := range testCases { plugin.HandleEndpoints(tc.eventType, tc.endpoints) if !router.Committed { t.Errorf("Expected router to be committed after HandleEndpoints call") } su, ok := router.FindServiceUnit(tc.expectedServiceUnit.Name) if !ok { t.Errorf("TestHandleEndpoints test case %s failed. Couldn't find expected service unit with name %s", tc.name, tc.expectedServiceUnit.Name) } else { for expectedKey, expectedEp := range tc.expectedServiceUnit.EndpointTable { actualEp := su.EndpointTable[expectedKey] if expectedEp.ID != actualEp.ID || expectedEp.IP != actualEp.IP || expectedEp.Port != actualEp.Port { t.Errorf("TestHandleEndpoints test case %s failed. Expected endpoint didn't match actual endpoint %v : %v", tc.name, expectedEp, actualEp) } } } } }