Skip to content

Commit 8834d91

Browse files
committed
router: add support for configuration by ingress
1 parent 7a315d5 commit 8834d91

File tree

18 files changed

+1763
-35
lines changed

18 files changed

+1763
-35
lines changed

Diff for: contrib/completions/bash/openshift

+4
Original file line numberDiff line numberDiff line change
@@ -20805,6 +20805,8 @@ _openshift_infra_f5-router()
2080520805
local_nonpersistent_flags+=("--context=")
2080620806
flags+=("--denied-domains=")
2080720807
local_nonpersistent_flags+=("--denied-domains=")
20808+
flags+=("--enable-ingress")
20809+
local_nonpersistent_flags+=("--enable-ingress")
2080820810
flags+=("--f5-host=")
2080920811
local_nonpersistent_flags+=("--f5-host=")
2081020812
flags+=("--f5-http-vserver=")
@@ -20988,6 +20990,8 @@ _openshift_infra_router()
2098820990
local_nonpersistent_flags+=("--default-certificate-path=")
2098920991
flags+=("--denied-domains=")
2099020992
local_nonpersistent_flags+=("--denied-domains=")
20993+
flags+=("--enable-ingress")
20994+
local_nonpersistent_flags+=("--enable-ingress")
2099120995
flags+=("--extended-validation")
2099220996
local_nonpersistent_flags+=("--extended-validation")
2099320997
flags+=("--fields=")

Diff for: contrib/completions/zsh/openshift

+4
Original file line numberDiff line numberDiff line change
@@ -20953,6 +20953,8 @@ _openshift_infra_f5-router()
2095320953
local_nonpersistent_flags+=("--context=")
2095420954
flags+=("--denied-domains=")
2095520955
local_nonpersistent_flags+=("--denied-domains=")
20956+
flags+=("--enable-ingress")
20957+
local_nonpersistent_flags+=("--enable-ingress")
2095620958
flags+=("--f5-host=")
2095720959
local_nonpersistent_flags+=("--f5-host=")
2095820960
flags+=("--f5-http-vserver=")
@@ -21136,6 +21138,8 @@ _openshift_infra_router()
2113621138
local_nonpersistent_flags+=("--default-certificate-path=")
2113721139
flags+=("--denied-domains=")
2113821140
local_nonpersistent_flags+=("--denied-domains=")
21141+
flags+=("--enable-ingress")
21142+
local_nonpersistent_flags+=("--enable-ingress")
2113921143
flags+=("--extended-validation")
2114021144
local_nonpersistent_flags+=("--extended-validation")
2114121145
flags+=("--fields=")

Diff for: docs/man/man1/openshift-infra-f5-router.1

+4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ You may restrict the set of routes exposed to a single project (with \-\-namespa
6767
\fB\-\-denied\-domains\fP=[]
6868
List of comma separated domains to deny in routes
6969

70+
.PP
71+
\fB\-\-enable\-ingress\fP=false
72+
Enable configuration via ingress resources
73+
7074
.PP
7175
\fB\-\-f5\-host\fP=""
7276
The host of F5 BIG\-IP's management interface

Diff for: docs/man/man1/openshift-infra-router.1

+4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ You may restrict the set of routes exposed to a single project (with \-\-namespa
8989
\fB\-\-denied\-domains\fP=[]
9090
List of comma separated domains to deny in routes
9191

92+
.PP
93+
\fB\-\-enable\-ingress\fP=false
94+
Enable configuration via ingress resources
95+
9296
.PP
9397
\fB\-\-extended\-validation\fP=true
9498
If set, then an additional extended validation step is performed on all routes admitted in by this router. Defaults to true and enables the extended validation checks.

Diff for: pkg/api/helpers.go

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package api
33
import (
44
"fmt"
55

6+
kapi "k8s.io/kubernetes/pkg/api"
67
"k8s.io/kubernetes/pkg/api/validation"
78
"k8s.io/kubernetes/pkg/api/validation/path"
89
)
@@ -33,3 +34,10 @@ func GetFieldLabelConversionFunc(supportedLabels map[string]string, overrideLabe
3334
return "", "", fmt.Errorf("field label not supported: %s", label)
3435
}
3536
}
37+
38+
// GetResourceKey returns a string of the form [namespace]/[name] for
39+
// the given resource. This is a common way of ensuring a key for a
40+
// resource that is unique across the cluster.
41+
func GetResourceKey(obj kapi.ObjectMeta) string {
42+
return fmt.Sprintf("%s/%s", obj.Namespace, obj.Name)
43+
}

Diff for: pkg/cmd/infra/router/f5.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func (o *F5RouterOptions) Run() error {
225225

226226
factory := o.RouterSelection.NewFactory(oc, kc)
227227
watchNodes := (len(o.InternalAddress) != 0 && len(o.VxlanGateway) != 0)
228-
controller := factory.Create(plugin, watchNodes)
228+
controller := factory.Create(plugin, watchNodes, o.EnableIngress)
229229
controller.Run()
230230

231231
select {}

Diff for: pkg/cmd/infra/router/router.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type RouterSelection struct {
5353

5454
AllowWildcardRoutes bool
5555
RestrictSubdomainOwnership bool
56+
57+
EnableIngress bool
5658
}
5759

5860
// Bind sets the appropriate labels
@@ -68,6 +70,7 @@ func (o *RouterSelection) Bind(flag *pflag.FlagSet) {
6870
flag.StringSliceVar(&o.DeniedDomains, "denied-domains", envVarAsStrings("ROUTER_DENIED_DOMAINS", "", ","), "List of comma separated domains to deny in routes")
6971
flag.StringSliceVar(&o.AllowedDomains, "allowed-domains", envVarAsStrings("ROUTER_ALLOWED_DOMAINS", "", ","), "List of comma separated domains to allow in routes. If specified, only the domains in this list will be allowed routes. Note that domains in the denied list take precedence over the ones in the allowed list")
7072
flag.BoolVar(&o.AllowWildcardRoutes, "allow-wildcard-routes", cmdutil.Env("ROUTER_ALLOW_WILDCARD_ROUTES", "") == "true", "Allow wildcard host names for routes")
73+
flag.BoolVar(&o.EnableIngress, "enable-ingress", cmdutil.Env("ROUTER_ENABLE_INGRESS", "") == "true", "Enable configuration via ingress resources")
7174
}
7275

7376
// RouteSelectionFunc returns a func that identifies the host for a route.
@@ -79,10 +82,14 @@ func (o *RouterSelection) RouteSelectionFunc() controller.RouteHostFunc {
7982
if !o.OverrideHostname && len(route.Spec.Host) > 0 {
8083
return route.Spec.Host
8184
}
85+
// GetNameForHost returns the ingress name for a generated route, and the route route
86+
// name otherwise. When a route and ingress in the same namespace share a name, the
87+
// route and the ingress' rules should receive the same generated host.
88+
nameForHost := controller.GetNameForHost(route.Name)
8289
s, err := variable.ExpandStrict(o.HostnameTemplate, func(key string) (string, bool) {
8390
switch key {
8491
case "name":
85-
return route.Name, true
92+
return nameForHost, true
8693
case "namespace":
8794
return route.Namespace, true
8895
default:

Diff for: pkg/cmd/infra/router/template.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func (o *TemplateRouterOptions) Run() error {
215215
plugin := controller.NewHostAdmitter(uniqueHostPlugin, o.RouteAdmissionFunc(), o.RestrictSubdomainOwnership, controller.RejectionRecorder(statusPlugin))
216216

217217
factory := o.RouterSelection.NewFactory(oc, kc)
218-
controller := factory.Create(plugin, false)
218+
controller := factory.Create(plugin, false, o.EnableIngress)
219219
controller.Run()
220220

221221
proc.StartReaper()

Diff for: pkg/route/api/v1/defaults.go

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ package v1
22

33
import "k8s.io/kubernetes/pkg/runtime"
44

5+
// If adding or changing route defaults, updates may be required to
6+
// pkg/router/controller/controller.go to ensure the routes generated from
7+
// ingress resources will match routes created via the api.
8+
59
func SetDefaults_RouteSpec(obj *RouteSpec) {
610
if len(obj.WildcardPolicy) == 0 {
711
obj.WildcardPolicy = WildcardPolicyNone

Diff for: pkg/router/controller/controller.go

+116-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/golang/glog"
99
kapi "k8s.io/kubernetes/pkg/api"
10+
"k8s.io/kubernetes/pkg/apis/extensions"
1011
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
1112
"k8s.io/kubernetes/pkg/util/sets"
1213
utilwait "k8s.io/kubernetes/pkg/util/wait"
@@ -30,25 +31,38 @@ type RouterController struct {
3031
NextRoute func() (watch.EventType, *routeapi.Route, error)
3132
NextNode func() (watch.EventType, *kapi.Node, error)
3233
NextEndpoints func() (watch.EventType, *kapi.Endpoints, error)
34+
NextIngress func() (watch.EventType, *extensions.Ingress, error)
35+
NextSecret func() (watch.EventType, *kapi.Secret, error)
3336

3437
RoutesListConsumed func() bool
3538
EndpointsListConsumed func() bool
39+
IngressesListConsumed func() bool
40+
SecretsListConsumed func() bool
3641
routesListConsumed bool
3742
endpointsListConsumed bool
43+
ingressesListConsumed bool
44+
secretsListConsumed bool
3845
filteredByNamespace bool
3946
syncing bool
4047

4148
RoutesListSuccessfulAtLeastOnce func() bool
4249
EndpointsListSuccessfulAtLeastOnce func() bool
50+
IngressesListSuccessfulAtLeastOnce func() bool
51+
SecretsListSuccessfulAtLeastOnce func() bool
4352
RoutesListCount func() int
4453
EndpointsListCount func() int
54+
IngressesListCount func() int
55+
SecretsListCount func() int
4556

4657
WatchNodes bool
4758

4859
Namespaces NamespaceLister
4960
NamespaceSyncInterval time.Duration
5061
NamespaceWaitInterval time.Duration
5162
NamespaceRetries int
63+
64+
EnableIngress bool
65+
IngressTranslator *IngressTranslator
5266
}
5367

5468
// Run begins watching and syncing.
@@ -63,6 +77,10 @@ func (c *RouterController) Run() {
6377
if c.WatchNodes {
6478
go utilwait.Forever(c.HandleNode, 0)
6579
}
80+
if c.EnableIngress {
81+
go utilwait.Forever(c.HandleIngress, 0)
82+
go utilwait.Forever(c.HandleSecret, 0)
83+
}
6684
go c.watchForFirstSync()
6785
}
6886

@@ -74,22 +92,31 @@ func (c *RouterController) handleFirstSync() bool {
7492

7593
synced := c.RoutesListSuccessfulAtLeastOnce() &&
7694
c.EndpointsListSuccessfulAtLeastOnce() &&
77-
(c.Namespaces == nil || c.filteredByNamespace)
95+
(c.Namespaces == nil || c.filteredByNamespace) &&
96+
(!c.EnableIngress ||
97+
(c.IngressesListSuccessfulAtLeastOnce() && c.SecretsListSuccessfulAtLeastOnce()))
7898
if !synced {
7999
return false
80100
}
81101

82-
// If either of the event queues were empty after the initial
83-
// List, the tracking listConsumed variable's default value of
84-
// 'false' may prevent the router from committing the readiness
85-
// status. Set the value to 'true' to ensure that state will be
86-
// committed if necessary.
102+
// If any of the event queues were empty after the initial List,
103+
// the tracking listConsumed variable's default value of 'false'
104+
// may prevent the router from committing. Set the value to
105+
// 'true' to ensure that state can be committed if necessary.
87106
if c.RoutesListCount() == 0 {
88107
c.routesListConsumed = true
89108
}
90109
if c.EndpointsListCount() == 0 {
91110
c.endpointsListConsumed = true
92111
}
112+
if c.EnableIngress {
113+
if c.IngressesListCount() == 0 {
114+
c.ingressesListConsumed = true
115+
}
116+
if c.SecretsListCount() == 0 {
117+
c.secretsListConsumed = true
118+
}
119+
}
93120
c.commit()
94121

95122
return true
@@ -109,6 +136,14 @@ func (c *RouterController) HandleNamespaces() {
109136
for i := 0; i < c.NamespaceRetries; i++ {
110137
namespaces, err := c.Namespaces.NamespaceNames()
111138
if err == nil {
139+
140+
// The ingress translator synchronizes access to its cache with a
141+
// lock, so calls to it are made outside of the controller lock to
142+
// avoid unintended interaction.
143+
if c.EnableIngress {
144+
c.IngressTranslator.UpdateNamespaces(namespaces)
145+
}
146+
112147
c.lock.Lock()
113148
defer c.lock.Unlock()
114149

@@ -161,13 +196,7 @@ func (c *RouterController) HandleRoute() {
161196
c.lock.Lock()
162197
defer c.lock.Unlock()
163198

164-
glog.V(4).Infof("Processing Route: %s -> %s", route.Name, route.Spec.To.Name)
165-
glog.V(4).Infof(" Alias: %s", route.Spec.Host)
166-
glog.V(4).Infof(" Event: %s", eventType)
167-
168-
if err := c.Plugin.HandleRoute(eventType, route); err != nil {
169-
utilruntime.HandleError(err)
170-
}
199+
c.processRoute(eventType, route)
171200

172201
// Change the local sync state within the lock to ensure that all
173202
// event handlers have the same view of sync state.
@@ -196,10 +225,61 @@ func (c *RouterController) HandleEndpoints() {
196225
c.commit()
197226
}
198227

228+
// HandleIngress handles a single Ingress event and synchronizes the router backend.
229+
func (c *RouterController) HandleIngress() {
230+
eventType, ingress, err := c.NextIngress()
231+
if err != nil {
232+
utilruntime.HandleError(fmt.Errorf("unable to read ingress: %v", err))
233+
return
234+
}
235+
236+
// The ingress translator synchronizes access to its cache with a
237+
// lock, so calls to it are made outside of the controller lock to
238+
// avoid unintended interaction.
239+
events := c.IngressTranslator.TranslateIngressEvent(eventType, ingress)
240+
241+
c.lock.Lock()
242+
defer c.lock.Unlock()
243+
244+
c.processIngressEvents(events)
245+
246+
// Change the local sync state within the lock to ensure that all
247+
// event handlers have the same view of sync state.
248+
c.ingressesListConsumed = c.IngressesListConsumed()
249+
c.commit()
250+
}
251+
252+
// HandleSecret handles a single Secret event and synchronizes the router backend.
253+
func (c *RouterController) HandleSecret() {
254+
eventType, secret, err := c.NextSecret()
255+
if err != nil {
256+
utilruntime.HandleError(fmt.Errorf("unable to read secret: %v", err))
257+
return
258+
259+
}
260+
261+
// The ingress translator synchronizes access to its cache with a
262+
// lock, so calls to it are made outside of the controller lock to
263+
// avoid unintended interaction.
264+
events := c.IngressTranslator.TranslateSecretEvent(eventType, secret)
265+
266+
c.lock.Lock()
267+
defer c.lock.Unlock()
268+
269+
c.processIngressEvents(events)
270+
271+
// Change the local sync state within the lock to ensure that all
272+
// event handlers have the same view of sync state.
273+
c.secretsListConsumed = c.SecretsListConsumed()
274+
c.commit()
275+
}
276+
199277
// commit notifies the plugin that it is safe to commit state.
200278
func (c *RouterController) commit() {
201279
syncing := !(c.endpointsListConsumed && c.routesListConsumed &&
202-
(c.Namespaces == nil || c.filteredByNamespace))
280+
(c.Namespaces == nil || c.filteredByNamespace) &&
281+
(!c.EnableIngress ||
282+
(c.ingressesListConsumed && c.secretsListConsumed)))
203283
c.logSyncState(syncing)
204284
if syncing {
205285
return
@@ -219,3 +299,25 @@ func (c *RouterController) logSyncState(syncing bool) {
219299
}
220300
}
221301
}
302+
303+
// processRoute logs and propagates a route event to the plugin
304+
func (c *RouterController) processRoute(eventType watch.EventType, route *routeapi.Route) {
305+
glog.V(4).Infof("Processing Route: %s/%s -> %s", route.Namespace, route.Name, route.Spec.To.Name)
306+
glog.V(4).Infof(" Alias: %s", route.Spec.Host)
307+
glog.V(4).Infof(" Path: %s", route.Spec.Path)
308+
glog.V(4).Infof(" Event: %s", eventType)
309+
310+
if err := c.Plugin.HandleRoute(eventType, route); err != nil {
311+
utilruntime.HandleError(err)
312+
}
313+
}
314+
315+
// processIngressEvents logs and propagates the route events resulting from an ingress or secret event
316+
func (c *RouterController) processIngressEvents(events []ingressRouteEvents) {
317+
for _, ingressEvent := range events {
318+
glog.V(4).Infof("Processing Ingress %s", ingressEvent.ingressKey)
319+
for _, routeEvent := range ingressEvent.routeEvents {
320+
c.processRoute(routeEvent.eventType, routeEvent.route)
321+
}
322+
}
323+
}

0 commit comments

Comments
 (0)