From 327ba9b52fa5e2c446d09355dcb15141c0f3472a Mon Sep 17 00:00:00 2001 From: ramr Date: Mon, 2 Apr 2018 14:55:03 -0700 Subject: [PATCH] Add support for a new plugin to manage blueprint routes and configure the manager appropriately. And some more changes as per review comments. --- hack/lib/start.sh | 7 + pkg/cmd/infra/router/template.go | 21 +- pkg/oc/admin/router/router.go | 13 +- .../configmanager/haproxy/blueprint_plugin.go | 55 +++++ .../haproxy/blueprint_plugin_test.go | 212 ++++++++++++++++++ .../template/configmanager/haproxy/manager.go | 166 +++++++++++--- pkg/router/template/types.go | 6 + test/end-to-end/router_test.go | 2 +- 8 files changed, 442 insertions(+), 40 deletions(-) create mode 100644 pkg/router/template/configmanager/haproxy/blueprint_plugin.go create mode 100644 pkg/router/template/configmanager/haproxy/blueprint_plugin_test.go diff --git a/hack/lib/start.sh b/hack/lib/start.sh index 4065aa4c3a1b..ad504fbd244e 100644 --- a/hack/lib/start.sh +++ b/hack/lib/start.sh @@ -615,6 +615,13 @@ function os::start::router() { oc adm router --config="${ADMIN_KUBECONFIG}" --images="${USE_IMAGES}" --service-account=router fi + # Note that when the haproxy config manager is set based on router type, + # the env entry may need to be always set or removed (if defaulted). + if [[ -n "${ROUTER_HAPROXY_CONFIG_MANAGER:-}" ]]; then + os::log::debug "Changing the router DC to enable the haproxy config manager" + oc set env dc/router -c router ROUTER_HAPROXY_CONFIG_MANAGER=true + fi + # Set the SYN eater to make router reloads more robust if [[ -n "${DROP_SYN_DURING_RESTART:-}" ]]; then # Rewrite the DC for the router to add the environment variable into the pod definition diff --git a/pkg/cmd/infra/router/template.go b/pkg/cmd/infra/router/template.go index fd698e1246e8..e6a3a14b2903 100644 --- a/pkg/cmd/infra/router/template.go +++ b/pkg/cmd/infra/router/template.go @@ -122,7 +122,7 @@ type TemplateRouter struct { } type TemplateRouterConfigManager struct { - ConfigManagerName string + UseHAProxyConfigManager bool CommitInterval time.Duration BlueprintRouteNamespace string BlueprintRouteLabelSelector string @@ -162,7 +162,7 @@ func (o *TemplateRouter) Bind(flag *pflag.FlagSet) { flag.StringVar(&o.Ciphers, "ciphers", util.Env("ROUTER_CIPHERS", ""), "Specifies the cipher suites to use. You can choose a predefined cipher set ('modern', 'intermediate', or 'old') or specify exact cipher suites by passing a : separated list.") flag.BoolVar(&o.StrictSNI, "strict-sni", isTrue(util.Env("ROUTER_STRICT_SNI", "")), "Use strict-sni bind processing (do not use default cert).") flag.StringVar(&o.MetricsType, "metrics-type", util.Env("ROUTER_METRICS_TYPE", ""), "Specifies the type of metrics to gather. Supports 'haproxy'.") - flag.StringVar(&o.ConfigManagerName, "config-manager", util.Env("ROUTER_CONFIG_MANAGER", ""), "Specifies the manager to use for dynamically configuring changes with the underlying router. Supports 'haproxy-manager'.") + flag.BoolVar(&o.UseHAProxyConfigManager, "haproxy-config-manager", isTrue(util.Env("ROUTER_HAPROXY_CONFIG_MANAGER", "")), "Use the the haproxy config manager (and dynamic configuration API) to configure route and endpoint changes. Reduces the number of haproxy reloads needed on configuration changes.") flag.DurationVar(&o.CommitInterval, "commit-interval", getIntervalFromEnv("COMMIT_INTERVAL", defaultCommitInterval), "Controls how often to commit (to the actual config) all the changes made using the router specific dynamic configuration manager.") flag.StringVar(&o.BlueprintRouteNamespace, "blueprint-route-namespace", util.Env("ROUTER_BLUEPRINT_ROUTE_NAMESPACE", ""), "Specifies the namespace which contains the routes that serve as blueprints for the dynamic configuration manager.") flag.StringVar(&o.BlueprintRouteLabelSelector, "blueprint-route-labels", util.Env("ROUTER_BLUEPRINT_ROUTE_LABELS", ""), "A label selector to apply to the routes in the blueprint route namespace. These selected routes will serve as blueprints for the dynamic dynamic configuration manager.") @@ -438,7 +438,8 @@ func (o *TemplateRouterOptions) Run() error { } var cfgManager templateplugin.ConfigManager - if o.ConfigManagerName == "haproxy-manager" { + var blueprintPlugin router.Plugin + if o.UseHAProxyConfigManager { blueprintRoutes, err := o.blueprintRoutes(routeclient) if err != nil { return err @@ -452,6 +453,9 @@ func (o *TemplateRouterOptions) Run() error { WildcardRoutesAllowed: o.AllowWildcardRoutes, } cfgManager = haproxyconfigmanager.NewHAProxyConfigManager(cmopts) + if len(o.BlueprintRouteNamespace) > 0 { + blueprintPlugin = haproxyconfigmanager.NewBlueprintPlugin(cfgManager) + } } pluginCfg := templateplugin.TemplatePluginConfig{ @@ -505,6 +509,17 @@ func (o *TemplateRouterOptions) Run() error { controller := factory.Create(plugin, false, o.EnableIngress) controller.Run() + if blueprintPlugin != nil { + // f is like factory but filters the routes based on the + // blueprint route namespace and label selector (if any). + f := o.RouterSelection.NewFactory(routeclient, projectclient.Project().Projects(), kc) + f.LabelSelector = o.BlueprintRouteLabelSelector + f.Namespace = o.BlueprintRouteNamespace + f.ResyncInterval = o.ResyncInterval + c := f.Create(blueprintPlugin, false, false) + c.Run() + } + proc.StartReaper() select {} diff --git a/pkg/oc/admin/router/router.go b/pkg/oc/admin/router/router.go index 4ba29379540c..cc699ab5eb63 100644 --- a/pkg/oc/admin/router/router.go +++ b/pkg/oc/admin/router/router.go @@ -684,14 +684,11 @@ func RunCmdRouter(f *clientcmd.Factory, cmd *cobra.Command, out, errout io.Write env["ROUTER_CANONICAL_HOSTNAME"] = cfg.RouterCanonicalHostname } // automatically start the internal metrics agent if we are handling a known type - if cfg.Type == "haproxy-router" { - env["ROUTER_CONFIG_MANAGER"] = "haproxy-manager" - if cfg.StatsPort != 0 { - env["ROUTER_LISTEN_ADDR"] = fmt.Sprintf("0.0.0.0:%d", cfg.StatsPort) - env["ROUTER_METRICS_TYPE"] = "haproxy" - env["ROUTER_METRICS_TLS_CERT_FILE"] = "/etc/pki/tls/metrics/tls.crt" - env["ROUTER_METRICS_TLS_KEY_FILE"] = "/etc/pki/tls/metrics/tls.key" - } + if cfg.Type == "haproxy-router" && cfg.StatsPort != 0 { + env["ROUTER_LISTEN_ADDR"] = fmt.Sprintf("0.0.0.0:%d", cfg.StatsPort) + env["ROUTER_METRICS_TYPE"] = "haproxy" + env["ROUTER_METRICS_TLS_CERT_FILE"] = "/etc/pki/tls/metrics/tls.crt" + env["ROUTER_METRICS_TLS_KEY_FILE"] = "/etc/pki/tls/metrics/tls.key" } env.Add(secretEnv) if len(defaultCert) > 0 { diff --git a/pkg/router/template/configmanager/haproxy/blueprint_plugin.go b/pkg/router/template/configmanager/haproxy/blueprint_plugin.go new file mode 100644 index 000000000000..fe0165993aab --- /dev/null +++ b/pkg/router/template/configmanager/haproxy/blueprint_plugin.go @@ -0,0 +1,55 @@ +package haproxy + +import ( + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/watch" + kapi "k8s.io/kubernetes/pkg/apis/core" + + routeapi "github.com/openshift/origin/pkg/route/apis/route" + templaterouter "github.com/openshift/origin/pkg/router/template" +) + +// BlueprintPlugin implements the router.Plugin interface to process routes +// from the blueprint namespace for the associated config manager. +type BlueprintPlugin struct { + manager templaterouter.ConfigManager +} + +// NewBlueprintPlugin returns a new blueprint routes plugin. +func NewBlueprintPlugin(cm templaterouter.ConfigManager) *BlueprintPlugin { + return &BlueprintPlugin{manager: cm} +} + +// HandleRoute processes watch events on blueprint routes. +func (p *BlueprintPlugin) HandleRoute(eventType watch.EventType, route *routeapi.Route) error { + switch eventType { + case watch.Added, watch.Modified: + p.manager.AddBlueprint(route) + case watch.Deleted: + p.manager.RemoveBlueprint(route) + } + + return nil +} + +// HandleNode processes watch events on the Node resource. +func (p *BlueprintPlugin) HandleNode(eventType watch.EventType, node *kapi.Node) error { + return nil +} + +// HandleEndpoints processes watch events on the Endpoints resource. +func (p *BlueprintPlugin) HandleEndpoints(eventType watch.EventType, endpoints *kapi.Endpoints) error { + return nil +} + +// HandleNamespaces processes watch events on namespaces. +func (p *BlueprintPlugin) HandleNamespaces(namespaces sets.String) error { + return nil +} + +// Commit commits the changes made to a watched resource. +func (p *BlueprintPlugin) Commit() error { + // Nothing to do as the config manager does an automatic commit when + // any blueprint routes change. + return nil +} diff --git a/pkg/router/template/configmanager/haproxy/blueprint_plugin_test.go b/pkg/router/template/configmanager/haproxy/blueprint_plugin_test.go new file mode 100644 index 000000000000..4da5cb1a5e81 --- /dev/null +++ b/pkg/router/template/configmanager/haproxy/blueprint_plugin_test.go @@ -0,0 +1,212 @@ +package haproxy + +import ( + "fmt" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/watch" + kapi "k8s.io/kubernetes/pkg/apis/core" + + routeapi "github.com/openshift/origin/pkg/route/apis/route" + templaterouter "github.com/openshift/origin/pkg/router/template" +) + +type fakeConfigManager struct { + blueprints map[string]*routeapi.Route +} + +func newFakeConfigManager() *fakeConfigManager { + return &fakeConfigManager{ + blueprints: make(map[string]*routeapi.Route), + } +} + +func (cm *fakeConfigManager) Initialize(router templaterouter.RouterInterface, certPath string) { +} + +func (cm *fakeConfigManager) AddBlueprint(route *routeapi.Route) { + cm.blueprints[routeKey(route)] = route +} + +func (cm *fakeConfigManager) RemoveBlueprint(route *routeapi.Route) { + delete(cm.blueprints, routeKey(route)) +} + +func (cm *fakeConfigManager) FindBlueprint(id string) (*routeapi.Route, bool) { + route, ok := cm.blueprints[id] + return route, ok +} + +func (cm *fakeConfigManager) Register(id string, route *routeapi.Route) { +} + +func (cm *fakeConfigManager) AddRoute(id string, route *routeapi.Route) error { + return nil +} + +func (cm *fakeConfigManager) RemoveRoute(id string, route *routeapi.Route) error { + return nil +} + +func (cm *fakeConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, newEndpoints []templaterouter.Endpoint, weight int32) error { + return nil +} + +func (cm *fakeConfigManager) RemoveRouteEndpoints(id string, endpoints []templaterouter.Endpoint) error { + return nil +} + +func (cm *fakeConfigManager) Notify(event templaterouter.RouterEventType) { +} + +func (cm *fakeConfigManager) ServerTemplateName(id string) string { + return "fakeConfigManager" +} + +func (cm *fakeConfigManager) ServerTemplateSize(id string) string { + return "1" +} + +func (cm *fakeConfigManager) GenerateDynamicServerNames(id string) []string { + return []string{} +} + +func routeKey(route *routeapi.Route) string { + return fmt.Sprintf("%s:%s", route.Name, route.Namespace) +} + +// TestHandleRoute test route watch events +func TestHandleRoute(t *testing.T) { + original := metav1.Time{Time: time.Now()} + + route := &routeapi.Route{ + ObjectMeta: metav1.ObjectMeta{ + CreationTimestamp: original, + Namespace: "bp", + Name: "chevron", + }, + Spec: routeapi.RouteSpec{ + Host: "www.blueprints.org", + To: routeapi.RouteTargetReference{ + Name: "TestService", + Weight: new(int32), + }, + }, + } + + cm := newFakeConfigManager() + plugin := NewBlueprintPlugin(cm) + plugin.HandleRoute(watch.Added, route) + + id := routeKey(route) + if _, ok := cm.FindBlueprint(id); !ok { + t.Errorf("TestHandleRoute was unable to find a blueprint %s after HandleRoute was called", id) + } + + // update a blueprint with a newer time and host + v2route := route.DeepCopy() + v2route.CreationTimestamp = metav1.Time{Time: original.Add(time.Hour)} + v2route.Spec.Host = "updated.blueprint.org" + if err := plugin.HandleRoute(watch.Added, v2route); err != nil { + t.Errorf("TestHandleRoute unexpected error after blueprint update: %v", err) + } + + blueprints := []*routeapi.Route{v2route, route} + for _, r := range blueprints { + // delete the blueprint and check that it doesn't exist. + if err := plugin.HandleRoute(watch.Deleted, v2route); err != nil { + t.Errorf("TestHandleRoute unexpected error after blueprint delete: %v", err) + } + + routeId := routeKey(r) + if _, ok := cm.FindBlueprint(routeId); ok { + t.Errorf("TestHandleRoute found a blueprint %s after it was deleted", routeId) + } + } +} + +func TestHandleNode(t *testing.T) { + node := &kapi.Node{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"design": "blueprint"}, + }, + } + + cm := newFakeConfigManager() + plugin := NewBlueprintPlugin(cm) + + if err := plugin.HandleNode(watch.Added, node); err != nil { + t.Errorf("TestHandleNode unexpected error after node add: %v", err) + } + + if err := plugin.HandleNode(watch.Modified, node); err != nil { + t.Errorf("TestHandleNode unexpected error after node modify: %v", err) + } + + if err := plugin.HandleNode(watch.Deleted, node); err != nil { + t.Errorf("TestHandleNode unexpected error after node delete: %v", err) + } +} + +func TestHandleEndpoints(t *testing.T) { + endpoints := &kapi.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "bpe", + Name: "shell", + }, + Subsets: []kapi.EndpointSubset{{ + Addresses: []kapi.EndpointAddress{{IP: "1.1.1.1"}}, + Ports: []kapi.EndpointPort{{Port: 9876}}, + }}, + } + + v2Endpoints := &kapi.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "bpe", + Name: "shell", + }, + Subsets: []kapi.EndpointSubset{{ + Addresses: []kapi.EndpointAddress{{IP: "1.1.1.1"}, {IP: "2.2.2.2"}}, + Ports: []kapi.EndpointPort{{Port: 9876}, {Port: 8888}}, + }}, + } + + cm := newFakeConfigManager() + plugin := NewBlueprintPlugin(cm) + + if err := plugin.HandleEndpoints(watch.Added, endpoints); err != nil { + t.Errorf("TestHandleEndpoints unexpected error after endpoints add: %v", err) + } + + if err := plugin.HandleEndpoints(watch.Modified, v2Endpoints); err != nil { + t.Errorf("TestHandleEndpoints unexpected error after endpoints modify: %v", err) + } + + if err := plugin.HandleEndpoints(watch.Deleted, v2Endpoints); err != nil { + t.Errorf("TestHandleEndpoints unexpected error after endpoints delete: %v", err) + } +} + +func TestHandleNamespaces(t *testing.T) { + cm := newFakeConfigManager() + plugin := NewBlueprintPlugin(cm) + + if err := plugin.HandleNamespaces(sets.String{}); err != nil { + t.Errorf("TestHandleNamespaces unexpected error after empty set: %v", err) + } + + if err := plugin.HandleNamespaces(sets.NewString("76")); err != nil { + t.Errorf("TestHandleNamespaces unexpected error after set: %v", err) + } + + if err := plugin.HandleNamespaces(sets.NewString("76", "711")); err != nil { + t.Errorf("TestHandleNamespaces unexpected error after set multiple: %v", err) + } + + if err := plugin.HandleNamespaces(sets.NewString("arco")); err != nil { + t.Errorf("TestHandleNamespaces unexpected error after reset: %v", err) + } +} diff --git a/pkg/router/template/configmanager/haproxy/manager.go b/pkg/router/template/configmanager/haproxy/manager.go index 0f176b363661..b6c2686f3c02 100644 --- a/pkg/router/template/configmanager/haproxy/manager.go +++ b/pkg/router/template/configmanager/haproxy/manager.go @@ -181,13 +181,92 @@ func (cm *haproxyConfigManager) Initialize(router templaterouter.RouterInterface cm.lock.Lock() cm.router = router cm.defaultCertificate = string(certBytes) + blueprints := cm.blueprintRoutes cm.lock.Unlock() - cm.provisionBackendPools() + // Ensure this is done outside of the lock as the router will call + // back into the manager code for all the routes we provision. + for _, r := range blueprints { + cm.provisionRoutePool(r) + } glog.V(2).Infof("haproxy Config Manager router will flush out any dynamically configured changes within %s of each other", cm.commitInterval.String()) } +// AddBlueprint adds a new (or replaces an existing) route blueprint. +func (cm *haproxyConfigManager) AddBlueprint(route *routeapi.Route) { + newRoute := route.DeepCopy() + newRoute.Namespace = blueprintRoutePoolNamespace + newRoute.Spec.Host = "" + + cm.lock.Lock() + existingBlueprints := cm.blueprintRoutes + cm.lock.Unlock() + + routeExists := false + updated := false + blueprints := make([]*routeapi.Route, 0) + for _, r := range existingBlueprints { + if r.Namespace == newRoute.Namespace && r.Name == newRoute.Name { + // Existing route, check if if anything changed, + // other than the host name. + routeExists = true + newRoute.Spec.Host = r.Spec.Host + if !reflect.DeepEqual(r, newRoute) { + updated = true + blueprints = append(blueprints, route.DeepCopy()) + continue + } + } + blueprints = append(blueprints, r) + } + + if !routeExists { + blueprints = append(blueprints, route.DeepCopy()) + updated = true + } + + if !updated { + return + } + + cm.lock.Lock() + cm.blueprintRoutes = blueprints + cm.lock.Unlock() + + cm.provisionRoutePool(route) +} + +// RemoveBlueprint removes a route blueprint. +func (cm *haproxyConfigManager) RemoveBlueprint(route *routeapi.Route) { + deletedRoute := route.DeepCopy() + deletedRoute.Namespace = blueprintRoutePoolNamespace + + cm.lock.Lock() + existingBlueprints := cm.blueprintRoutes + cm.lock.Unlock() + + updated := false + blueprints := make([]*routeapi.Route, 0) + for _, r := range existingBlueprints { + if r.Namespace == deletedRoute.Namespace && r.Name == deletedRoute.Name { + updated = true + } else { + blueprints = append(blueprints, r) + } + } + + if !updated { + return + } + + cm.lock.Lock() + cm.blueprintRoutes = blueprints + cm.lock.Unlock() + + cm.removeRoutePool(route) +} + // Register registers an id with an expected haproxy backend for a route. func (cm *haproxyConfigManager) Register(id string, route *routeapi.Route) { wildcard := cm.wildcardRoutesAllowed && (route.Spec.WildcardPolicy == routeapi.WildcardPolicySubdomain) @@ -226,7 +305,10 @@ func (cm *haproxyConfigManager) AddRoute(id string, route *routeapi.Route) error cm.Register(id, route) cm.lock.Lock() - defer cm.lock.Unlock() + defer func() { + cm.lock.Unlock() + cm.scheduleRouterReload() + }() slotName, err := cm.findFreeBackendPoolSlot(matchedBlueprint) if err != nil { @@ -268,7 +350,10 @@ func (cm *haproxyConfigManager) RemoveRoute(id string, route *routeapi.Route) er } cm.lock.Lock() - defer cm.lock.Unlock() + defer func() { + cm.lock.Unlock() + cm.scheduleRouterReload() + }() entry, ok := cm.backendEntries[id] if !ok { @@ -315,8 +400,14 @@ func (cm *haproxyConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, n return fmt.Errorf("Router reload in progress, cannot dynamically add endpoints for %s", id) } + configChanged := false cm.lock.Lock() - defer cm.lock.Unlock() + defer func() { + cm.lock.Unlock() + if configChanged { + cm.scheduleRouterReload() + } + }() entry, ok := cm.backendEntries[id] if !ok { @@ -355,6 +446,7 @@ func (cm *haproxyConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, n delete(modifiedEndpoints, v2ep.ID) } } else { + configChanged = true deletedEndpoints[ep.ID] = ep } } @@ -384,6 +476,7 @@ func (cm *haproxyConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, n } if _, ok := deletedEndpoints[relatedEndpointID]; ok { + configChanged = true glog.V(4).Infof("For deleted endpoint %s, disabling server %s", relatedEndpointID, s.Name) backend.DisableServer(s.Name) if _, ok := entry.dynamicServerMap[s.Name]; ok { @@ -394,6 +487,7 @@ func (cm *haproxyConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, n } if ep, ok := modifiedEndpoints[relatedEndpointID]; ok { + configChanged = true glog.V(4).Infof("For modified endpoint %s, setting server %s info to %s:%s with weight %d and enabling", relatedEndpointID, s.Name, ep.IP, ep.Port, weight) backend.UpdateServerInfo(s.Name, ep.IP, ep.Port, weight, weightIsRelative) @@ -419,6 +513,7 @@ func (cm *haproxyConfigManager) ReplaceRouteEndpoints(id string, oldEndpoints, n } // Add entry for the dyamic server used. + configChanged = true entry.dynamicServerMap[name] = ep.ID glog.V(4).Infof("For added endpoint %s, setting dynamic server %s info: (%s, %s, %d) and enabling", ep.ID, name, ep.IP, ep.Port, weight) @@ -447,7 +542,10 @@ func (cm *haproxyConfigManager) RemoveRouteEndpoints(id string, endpoints []temp } cm.lock.Lock() - defer cm.lock.Unlock() + defer func() { + cm.lock.Unlock() + cm.scheduleRouterReload() + }() entry, ok := cm.backendEntries[id] if !ok { @@ -503,17 +601,10 @@ func (cm *haproxyConfigManager) Notify(event templaterouter.RouterEventType) { } } -// Commit defers calling commit on the associated template router using a -// internal flush timer. +// Commit commits the configuration and reloads the associated router. func (cm *haproxyConfigManager) Commit() { glog.V(4).Infof("Committing dynamic config manager changes") - - cm.lock.Lock() - defer cm.lock.Unlock() - - if cm.commitTimer == nil { - cm.commitTimer = time.AfterFunc(cm.commitInterval, cm.commitRouterConfig) - } + cm.commitRouterConfig() } // ServerTemplateName returns the dynamic server template name. @@ -551,6 +642,16 @@ func (cm *haproxyConfigManager) GenerateDynamicServerNames(id string) []string { return []string{} } +// scheduleRouterReload schedules a reload by deferring commit on the +// associated template router using a internal flush timer. +func (cm *haproxyConfigManager) scheduleRouterReload() { + cm.lock.Lock() + defer cm.lock.Unlock() + if cm.commitTimer == nil { + cm.commitTimer = time.AfterFunc(cm.commitInterval, cm.commitRouterConfig) + } +} + // commitRouterConfig calls Commit on the associated template router. func (cm *haproxyConfigManager) commitRouterConfig() { cm.lock.Lock() @@ -581,20 +682,29 @@ func (cm *haproxyConfigManager) isManagedPoolRoute(route *routeapi.Route) bool { return route.Namespace == blueprintRoutePoolNamespace } -// provisionBackendPools pre-allocates pools of backends based on the -// different blueprint routes. -func (cm *haproxyConfigManager) provisionBackendPools() { - for _, r := range cm.blueprintRoutes { - poolSize := getPoolSize(r, cm.blueprintRoutePoolSize) - glog.Infof("Provisioning blueprint route pool %s/%s-[1-%d]", - r.Namespace, r.Name, poolSize) - for i := 0; i < poolSize; i++ { - route := r.DeepCopy() - route.Namespace = blueprintRoutePoolNamespace - route.Name = fmt.Sprintf("%v-%v", route.Name, i+1) - route.Spec.Host = "" - cm.router.AddRoute(route) - } +// provisionRoutePool provisions a pre-allocated pool of routes based on a blueprint. +func (cm *haproxyConfigManager) provisionRoutePool(blueprint *routeapi.Route) { + poolSize := getPoolSize(blueprint, cm.blueprintRoutePoolSize) + glog.Infof("Provisioning blueprint route pool %s/%s-[1-%d]", blueprint.Namespace, blueprint.Name, poolSize) + for i := 0; i < poolSize; i++ { + route := blueprint.DeepCopy() + route.Namespace = blueprintRoutePoolNamespace + route.Name = fmt.Sprintf("%v-%v", route.Name, i+1) + route.Spec.Host = "" + cm.router.AddRoute(route) + } +} + +// removeRoutePool removes a pre-allocated pool of routes based on a blueprint. +func (cm *haproxyConfigManager) removeRoutePool(blueprint *routeapi.Route) { + poolSize := getPoolSize(blueprint, cm.blueprintRoutePoolSize) + glog.Infof("Removing blueprint route pool %s/%s-[1-%d]", blueprint.Namespace, blueprint.Name, poolSize) + for i := 0; i < poolSize; i++ { + route := blueprint.DeepCopy() + route.Namespace = blueprintRoutePoolNamespace + route.Name = fmt.Sprintf("%v-%v", route.Name, i+1) + route.Spec.Host = "" + cm.router.RemoveRoute(route) } } diff --git a/pkg/router/template/types.go b/pkg/router/template/types.go index b09fbc4b9347..edebd5310c48 100644 --- a/pkg/router/template/types.go +++ b/pkg/router/template/types.go @@ -180,6 +180,12 @@ type ConfigManager interface { // Initialize initializes the config manager. Initialize(router RouterInterface, certPath string) + // AddBlueprint adds a new (or replaces an existing) route blueprint. + AddBlueprint(route *routeapi.Route) + + // RemoveBlueprint removes a route blueprint. + RemoveBlueprint(route *routeapi.Route) + // Register registers an id to be associated with a route. Register(id string, route *routeapi.Route) diff --git a/test/end-to-end/router_test.go b/test/end-to-end/router_test.go index ded53949f3b5..2e849e7ec33f 100644 --- a/test/end-to-end/router_test.go +++ b/test/end-to-end/router_test.go @@ -1324,7 +1324,7 @@ func createAndStartRouterContainerExtended(dockerCli *dockerClient.Client, maste fmt.Sprintf("ROUTER_BIND_PORTS_AFTER_SYNC=%s", strconv.FormatBool(bindPortsAfterSync)), fmt.Sprintf("ROUTER_ENABLE_INGRESS=%s", strconv.FormatBool(enableIngress)), fmt.Sprintf("NAMESPACE_LABELS=%s", namespaceLabels), - fmt.Sprintf("ROUTER_CONFIG_MANAGER=haproxy-manager"), + fmt.Sprintf("ROUTER_HAPROXY_CONFIG_MANAGER=true"), } reloadIntVar := fmt.Sprintf("RELOAD_INTERVAL=%ds", reloadInterval)