Skip to content

Commit

Permalink
Merge pull request #5725 from smarterclayton/override_route_host
Browse files Browse the repository at this point in the history
Merged by openshift-bot
  • Loading branch information
OpenShift Bot committed Dec 16, 2015
2 parents f7e2d9d + 35c68f4 commit 0d4de0b
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 11 deletions.
4 changes: 4 additions & 0 deletions contrib/completions/bash/openshift
Original file line number Diff line number Diff line change
Expand Up @@ -14164,6 +14164,7 @@ _openshift_infra_router()
flags+=("--context=")
flags+=("--default-certificate=")
flags+=("--fields=")
flags+=("--hostname-template=")
flags+=("--include-udp-endpoints")
flags+=("--insecure-skip-tls-verify")
flags+=("--kubernetes=")
Expand All @@ -14172,6 +14173,7 @@ _openshift_infra_router()
flags+=("--namespace=")
two_word_flags+=("-n")
flags+=("--namespace-labels=")
flags+=("--override-hostname")
flags+=("--project-labels=")
flags+=("--reload=")
flags+=("--resync-interval=")
Expand Down Expand Up @@ -14242,6 +14244,7 @@ _openshift_infra_f5-router()
flags+=("--f5-private-key=")
flags+=("--f5-username=")
flags+=("--fields=")
flags+=("--hostname-template=")
flags+=("--include-udp-endpoints")
flags+=("--insecure-skip-tls-verify")
flags+=("--kubernetes=")
Expand All @@ -14250,6 +14253,7 @@ _openshift_infra_f5-router()
flags+=("--namespace=")
two_word_flags+=("-n")
flags+=("--namespace-labels=")
flags+=("--override-hostname")
flags+=("--project-labels=")
flags+=("--resync-interval=")
flags+=("--server=")
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/infra/router/f5.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (o *F5RouterOptions) Run() error {
return err
}

plugin := controller.NewUniqueHost(f5Plugin, controller.HostForRoute)
plugin := controller.NewUniqueHost(f5Plugin, o.RouteSelectionFunc())

oc, kc, err := o.Config.Clients()
if err != nil {
Expand Down
38 changes: 38 additions & 0 deletions pkg/cmd/infra/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package router

import (
"fmt"
"strings"
"time"

"github.com/golang/glog"
Expand All @@ -14,6 +15,9 @@ import (

oclient "github.com/openshift/origin/pkg/client"
cmdutil "github.com/openshift/origin/pkg/cmd/util"
"github.com/openshift/origin/pkg/cmd/util/variable"
routeapi "github.com/openshift/origin/pkg/route/api"
"github.com/openshift/origin/pkg/router/controller"
controllerfactory "github.com/openshift/origin/pkg/router/controller/factory"
)

Expand All @@ -22,6 +26,9 @@ import (
type RouterSelection struct {
ResyncInterval time.Duration

HostnameTemplate string
OverrideHostname bool

LabelSelector string
Labels labels.Selector
FieldSelector string
Expand All @@ -40,16 +47,47 @@ type RouterSelection struct {
// Bind sets the appropriate labels
func (o *RouterSelection) Bind(flag *pflag.FlagSet) {
flag.DurationVar(&o.ResyncInterval, "resync-interval", 10*time.Minute, "The interval at which the route list should be fully refreshed")
flag.StringVar(&o.HostnameTemplate, "hostname-template", cmdutil.Env("ROUTER_SUBDOMAIN", ""), "If specified, a template that should be used to generate the hostname for a route without spec.host (e.g. '${name}-${namespace}.myapps.mycompany.com')")
flag.BoolVar(&o.OverrideHostname, "override-hostname", false, "Override the spec.host value for a route with --hostname-template")
flag.StringVar(&o.LabelSelector, "labels", cmdutil.Env("ROUTE_LABELS", ""), "A label selector to apply to the routes to watch")
flag.StringVar(&o.FieldSelector, "fields", cmdutil.Env("ROUTE_FIELDS", ""), "A field selector to apply to routes to watch")
flag.StringVar(&o.ProjectLabelSelector, "project-labels", cmdutil.Env("PROJECT_LABELS", ""), "A label selector to apply to projects to watch; if '*' watches all projects the client can access")
flag.StringVar(&o.NamespaceLabelSelector, "namespace-labels", cmdutil.Env("NAMESPACE_LABELS", ""), "A label selector to apply to namespaces to watch")
flag.BoolVar(&o.IncludeUDP, "include-udp-endpoints", false, "If true, UDP endpoints will be considered as candidates for routing")
}

// RouteSelectionFunc returns a func that identifies the host for a route.
func (o *RouterSelection) RouteSelectionFunc() controller.RouteHostFunc {
if len(o.HostnameTemplate) == 0 {
return controller.HostForRoute
}
return func(route *routeapi.Route) string {
if !o.OverrideHostname && len(route.Spec.Host) > 0 {
return route.Spec.Host
}
s, err := variable.ExpandStrict(o.HostnameTemplate, func(key string) (string, bool) {
switch key {
case "name":
return route.Name, true
case "namespace":
return route.Namespace, true
default:
return "", false
}
})
if err != nil {
return ""
}
return strings.Trim(s, "\"'")
}
}

// Complete converts string representations of field and label selectors to their parsed equivalent, or
// returns an error.
func (o *RouterSelection) Complete() error {
if len(o.HostnameTemplate) == 0 && o.OverrideHostname {
return fmt.Errorf("--override-hostname requires that --hostname-template be specified")
}
if len(o.LabelSelector) > 0 {
s, err := labels.Parse(o.LabelSelector)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/infra/router/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func (o *TemplateRouterOptions) Run() error {
return err
}

plugin := controller.NewUniqueHost(templatePlugin, controller.HostForRoute)
plugin := controller.NewUniqueHost(templatePlugin, o.RouteSelectionFunc())

oc, kc, err := o.Config.Clients()
if err != nil {
Expand Down
38 changes: 34 additions & 4 deletions test/extended/fixtures/scoped-router.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
apiVersion: v1
kind: List
items:
# a scoped router
- apiVersion: v1
kind: Pod
metadata:
name: router
name: scoped-router
labels:
test: router
test: scoped-router
spec:
containers:
- name: router
Expand All @@ -17,6 +18,7 @@ items:
fieldRef:
fieldPath: metadata.namespace
args: ["--namespace=$(POD_NAMESPACE)", "--loglevel=4", "--labels=select=first"]
hostNetwork: false
ports:
- containerPort: 80
- containerPort: 443
Expand All @@ -25,16 +27,43 @@ items:
protocol: TCP
serviceAccountName: default

# a router that overrides host
- apiVersion: v1
kind: Pod
metadata:
name: router-override
labels:
test: router-override
spec:
containers:
- name: router
image: openshift/origin-haproxy-router
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args: ["--namespace=$(POD_NAMESPACE)", "--loglevel=4", "--override-hostname", "--hostname-template=${name}-${namespace}.myapps.mycompany.com"]
hostNetwork: false
ports:
- containerPort: 80
- containerPort: 443
- containerPort: 1936
name: stats
protocol: TCP
serviceAccountName: default


# ensure the router can access routes and endpoints
- apiVersion: v1
kind: RoleBinding
metadata:
name: view
name: system-router
subjects:
- kind: ServiceAccount
name: default
roleRef:
name: view
name: system:router

# two routes that differ only by their labels and names
- apiVersion: v1
Expand Down Expand Up @@ -89,6 +118,7 @@ items:
containers:
- name: test
image: openshift/hello-openshift
# image: openshift/deployment-example:v1
ports:
- containerPort: 8080
name: http
Expand Down
78 changes: 73 additions & 5 deletions test/extended/router/scoped.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,22 @@ var _ = g.Describe("Router", func() {
configPath = exutil.FixturePath("fixtures", "scoped-router.yaml")
oc = exutil.NewCLI("scoped-router", exutil.KubeConfigPath())
)

g.BeforeEach(func() {
// defer oc.Run("delete").Args("-f", configPath).Execute()
err := oc.Run("create").Args("-f", configPath).Execute()
o.Expect(err).NotTo(o.HaveOccurred())
})

g.Describe("The HAProxy router", func() {
g.It("should serve the correct routes when scoped to a single namespace and label set", func() {
oc.SetOutputDir(exutil.TestContext.OutputDir)

g.By(fmt.Sprintf("creating a scoped router from a config file %q", configPath))
err := oc.Run("create").Args("-f", configPath).Execute()
o.Expect(err).NotTo(o.HaveOccurred())

var routerIP string
err = wait.Poll(time.Second, 2*time.Minute, func() (bool, error) {
pod, err := oc.KubeFramework().Client.Pods(oc.KubeFramework().Namespace.Name).Get("router")
err := wait.Poll(time.Second, 2*time.Minute, func() (bool, error) {
pod, err := oc.KubeFramework().Client.Pods(oc.KubeFramework().Namespace.Name).Get("scoped-router")
if err != nil {
return false, err
}
Expand All @@ -45,6 +50,11 @@ var _ = g.Describe("Router", func() {
// router expected to listen on port 80
routerURL := fmt.Sprintf("http://%s", routerIP)

g.By("waiting for the healthz endpoint to respond")
healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP)
err = waitForRouterOKResponse(healthzURI, routerIP, 2*time.Minute)
o.Expect(err).NotTo(o.HaveOccurred())

g.By("waiting for the valid route to respond")
err = waitForRouterOKResponse(routerURL, "first.example.com", 2*time.Minute)
o.Expect(err).NotTo(o.HaveOccurred())
Expand All @@ -61,6 +71,64 @@ var _ = g.Describe("Router", func() {
}
}
})
g.It("should override the route host with a custom value", func() {
oc.SetOutputDir(exutil.TestContext.OutputDir)
ns := oc.KubeFramework().Namespace.Name

g.By(fmt.Sprintf("creating a scoped router from a config file %q", configPath))

var routerIP string
err := wait.Poll(time.Second, 2*time.Minute, func() (bool, error) {
pod, err := oc.KubeFramework().Client.Pods(ns).Get("router-override")
if err != nil {
return false, err
}
if len(pod.Status.PodIP) == 0 {
return false, nil
}
routerIP = pod.Status.PodIP
return true, nil
})

o.Expect(err).NotTo(o.HaveOccurred())

// router expected to listen on port 80
routerURL := fmt.Sprintf("http://%s", routerIP)
pattern := "%s-%s.myapps.mycompany.com"

g.By("waiting for the healthz endpoint to respond")
healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP)
err = waitForRouterOKResponse(healthzURI, routerIP, 2*time.Minute)
o.Expect(err).NotTo(o.HaveOccurred())

g.By("waiting for the valid route to respond")
err = waitForRouterOKResponse(routerURL, fmt.Sprintf(pattern, "route-1", ns), 2*time.Minute)
o.Expect(err).NotTo(o.HaveOccurred())

g.By("checking that the stored domain name does not match a route")
host := "first.example.com"
req, err := requestViaReverseProxy("GET", routerURL, host)
o.Expect(err).NotTo(o.HaveOccurred())
resp, err := http.DefaultClient.Do(req)
o.Expect(err).NotTo(o.HaveOccurred())
resp.Body.Close()
if resp.StatusCode != http.StatusServiceUnavailable {
e2e.Failf("should have had a 503 status code for %s", host)
}

for _, host := range []string{"route-1", "route-2"} {
host = fmt.Sprintf(pattern, host, ns)
g.By(fmt.Sprintf("checking that %s does not match a route", host))
req, err := requestViaReverseProxy("GET", routerURL, host)
o.Expect(err).NotTo(o.HaveOccurred())
resp, err := http.DefaultClient.Do(req)
o.Expect(err).NotTo(o.HaveOccurred())
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
e2e.Failf("should have had a 200 status code for %s", host)
}
}
})
})
})

Expand All @@ -72,7 +140,7 @@ func waitForRouterOKResponse(url, host string, timeout time.Duration) error {
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return false, err
return false, nil
}
resp.Body.Close()
if resp.StatusCode == http.StatusServiceUnavailable {
Expand Down

0 comments on commit 0d4de0b

Please sign in to comment.