Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Override routes from certain domains with the hostname template #19418

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion pkg/cmd/infra/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type RouterSelection struct {

HostnameTemplate string
OverrideHostname bool
OverrideDomains []string
RedactedDomains sets.String

LabelSelector string
FieldSelector string
Expand Down Expand Up @@ -71,6 +73,7 @@ func (o *RouterSelection) Bind(flag *pflag.FlagSet) {
flag.DurationVar(&o.ResyncInterval, "resync-interval", controllerfactory.DefaultResyncInterval, "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", isTrue(cmdutil.Env("ROUTER_OVERRIDE_HOSTNAME", "")), "Override the spec.host value for a route with --hostname-template")
flag.StringSliceVar(&o.OverrideDomains, "override-domains", envVarAsStrings("ROUTER_OVERRIDE_DOMAINS", "", ","), "List of comma separated domains to override if present in any routes. This overrides the spec.host value in any matching routes 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")
Expand All @@ -91,7 +94,7 @@ func (o *RouterSelection) RouteUpdate(route *routeapi.Route) {
if len(o.HostnameTemplate) == 0 {
return
}
if !o.OverrideHostname && len(route.Spec.Host) > 0 {
if !o.OverrideHostname && len(route.Spec.Host) > 0 && !hostInDomainList(route.Spec.Host, o.RedactedDomains) {
return
}
s, err := variable.ExpandStrict(o.HostnameTemplate, func(key string) (string, bool) {
Expand Down Expand Up @@ -166,6 +169,12 @@ func (o *RouterSelection) Complete() error {
if len(o.HostnameTemplate) == 0 && o.OverrideHostname {
return fmt.Errorf("--override-hostname requires that --hostname-template be specified")
}

o.RedactedDomains = sets.NewString(o.OverrideDomains...)
if len(o.RedactedDomains) > 0 && len(o.HostnameTemplate) == 0 {
return fmt.Errorf("--override-domains requires that --hostname-template be specified")
}

if len(o.LabelSelector) > 0 {
if _, err := labels.Parse(o.LabelSelector); err != nil {
return fmt.Errorf("label selector is not valid: %v", err)
Expand Down
59 changes: 59 additions & 0 deletions test/extended/router/scoped.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,65 @@ var _ = g.Describe("[Conformance][Area:Networking][Feature:Router]", func() {
o.Expect(status).To(o.Equal(kapi.ConditionTrue))
o.Expect(condition.LastTransitionTime).NotTo(o.BeNil())
})

g.It("should override the route host for overridden domains with a custom value", func() {
oc.SetOutputDir(exutil.TestContext.OutputDir)
ns := oc.KubeFramework().Namespace.Name
execPodName := exutil.CreateExecPodOrFail(oc.AdminKubeClient().CoreV1(), ns, "execpod")
defer func() { oc.AdminKubeClient().CoreV1().Pods(ns).Delete(execPodName, metav1.NewDeleteOptions(1)) }()

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

var routerIP string
err := wait.Poll(time.Second, changeTimeoutSeconds*time.Second, func() (bool, error) {
pod, err := oc.KubeFramework().ClientSet.CoreV1().Pods(ns).Get("router-override-domains", metav1.GetOptions{})
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.apps.veto.test"

g.By("waiting for the healthz endpoint to respond")
healthzURI := fmt.Sprintf("http://%s:1936/healthz", routerIP)
err = waitForRouterOKResponseExec(ns, execPodName, healthzURI, routerIP, changeTimeoutSeconds)
o.Expect(err).NotTo(o.HaveOccurred())

g.By("waiting for the valid route to respond")
err = waitForRouterOKResponseExec(ns, execPodName, routerURL+"/Letter", fmt.Sprintf(pattern, "route-override-domain-1", ns), changeTimeoutSeconds)
o.Expect(err).NotTo(o.HaveOccurred())

g.By("checking that the stored domain name does not match a route")
host := "y.a.null.ptr"
err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusServiceUnavailable)
o.Expect(err).NotTo(o.HaveOccurred())

for _, host := range []string{"route-override-domain-1", "route-override-domain-2"} {
host = fmt.Sprintf(pattern, host, ns)
g.By(fmt.Sprintf("checking that %s matches a route", host))
err = expectRouteStatusCodeExec(ns, execPodName, routerURL+"/Letter", host, http.StatusOK)
o.Expect(err).NotTo(o.HaveOccurred())
}

g.By("checking that the router reported the correct ingress and override")
r, err := oc.RouteClient().Route().Routes(ns).Get("route-override-domain-2", metav1.GetOptions{})
o.Expect(err).NotTo(o.HaveOccurred())
ingress := ingressForName(r, "test-override-domains")
o.Expect(ingress).NotTo(o.BeNil())
o.Expect(ingress.Host).To(o.Equal(fmt.Sprintf(pattern, "route-override-domain-2", ns)))
status, condition := routeapi.IngressConditionStatus(ingress, routeapi.RouteAdmitted)
o.Expect(status).To(o.Equal(kapi.ConditionTrue))
o.Expect(condition.LastTransitionTime).NotTo(o.BeNil())
})
})
})

Expand Down
58 changes: 58 additions & 0 deletions test/extended/testdata/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions test/extended/testdata/scoped-router.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,34 @@ objects:
protocol: TCP
serviceAccountName: default

# a router that overrides domains
- apiVersion: v1
kind: Pod
metadata:
name: router-override-domains
labels:
test: router-override-domains
spec:
terminationGracePeriodSeconds: 1
containers:
- name: router
image: ${IMAGE}
imagePullPolicy: IfNotPresent
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
args: ["--name=test-override-domains", "--namespace=$(POD_NAMESPACE)", "--loglevel=4", "--override-domains=null.ptr,void.str", "--hostname-template=${name}-${namespace}.apps.veto.test"]
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
Expand Down Expand Up @@ -104,6 +132,36 @@ objects:
ports:
- targetPort: http

# routes that contain overridden domains
- apiVersion: v1
kind: Route
metadata:
name: route-override-domain-1
labels:
test: router
select: override-domains
spec:
host: y.a.null.ptr
path: /Letter
to:
name: endpoints
ports:
- targetPort: 8080
- apiVersion: v1
kind: Route
metadata:
name: route-override-domain-2
labels:
test: router
select: override-domains
spec:
host: main.void.str
path: /Letter
to:
name: endpoints
ports:
- targetPort: 8080

# a service to be routed to
- apiVersion: v1
kind: Service
Expand Down