Skip to content

Commit 277c406

Browse files
committed
router: add support for configuration by ingress
1 parent ba5e5e9 commit 277c406

File tree

17 files changed

+1656
-35
lines changed

17 files changed

+1656
-35
lines changed

contrib/completions/bash/openshift

+2
Original file line numberDiff line numberDiff line change
@@ -20646,6 +20646,8 @@ _openshift_infra_router()
2064620646
local_nonpersistent_flags+=("--default-certificate-path=")
2064720647
flags+=("--denied-domains=")
2064820648
local_nonpersistent_flags+=("--denied-domains=")
20649+
flags+=("--enable-ingress")
20650+
local_nonpersistent_flags+=("--enable-ingress")
2064920651
flags+=("--extended-validation")
2065020652
local_nonpersistent_flags+=("--extended-validation")
2065120653
flags+=("--fields=")

contrib/completions/zsh/openshift

+2
Original file line numberDiff line numberDiff line change
@@ -20794,6 +20794,8 @@ _openshift_infra_router()
2079420794
local_nonpersistent_flags+=("--default-certificate-path=")
2079520795
flags+=("--denied-domains=")
2079620796
local_nonpersistent_flags+=("--denied-domains=")
20797+
flags+=("--enable-ingress")
20798+
local_nonpersistent_flags+=("--enable-ingress")
2079720799
flags+=("--extended-validation")
2079820800
local_nonpersistent_flags+=("--extended-validation")
2079920801
flags+=("--fields=")

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 ingress resource configuration of the router
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.

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+
}

pkg/cmd/infra/router/f5.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ 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+
// TODO should ingress be configurable for f5?
229+
controller := factory.Create(plugin, watchNodes, false)
229230
controller.Run()
230231

231232
select {}

pkg/cmd/infra/router/router.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,22 @@ func (o *RouterSelection) RouteSelectionFunc() controller.RouteHostFunc {
7979
if !o.OverrideHostname && len(route.Spec.Host) > 0 {
8080
return route.Spec.Host
8181
}
82+
nameForHost := route.Name
83+
if controller.IsGeneratedRoute(route) {
84+
// Use the resource name embedded in the route name to
85+
// construct the host. The name of routes generated from
86+
// ingress rules will be 'ingress/[name]/[host]/[path]'.
87+
//
88+
// When a route and ingress in the same namespace share a
89+
// name, the route and the ingress' rules should receive
90+
// the same generated host.
91+
nameParts := strings.Split(nameForHost, "/")
92+
nameForHost = nameParts[1]
93+
}
8294
s, err := variable.ExpandStrict(o.HostnameTemplate, func(key string) (string, bool) {
8395
switch key {
8496
case "name":
85-
return route.Name, true
97+
return nameForHost, true
8698
case "namespace":
8799
return route.Namespace, true
88100
default:

pkg/cmd/infra/router/template.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type TemplateRouter struct {
6363
ExtendedValidation bool
6464
RouterService *ktypes.NamespacedName
6565
BindPortsAfterSync bool
66+
EnableIngress bool
6667
}
6768

6869
// reloadInterval returns how often to run the router reloads. The interval
@@ -88,6 +89,7 @@ func (o *TemplateRouter) Bind(flag *pflag.FlagSet) {
8889
flag.DurationVar(&o.ReloadInterval, "interval", reloadInterval(), "Controls how often router reloads are invoked. Mutiple router reload requests are coalesced for the duration of this interval since the last reload time.")
8990
flag.BoolVar(&o.ExtendedValidation, "extended-validation", util.Env("EXTENDED_VALIDATION", "true") == "true", "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.")
9091
flag.BoolVar(&o.BindPortsAfterSync, "bind-ports-after-sync", util.Env("ROUTER_BIND_PORTS_AFTER_SYNC", "") == "true", "Bind ports only after route state has been synchronized")
92+
flag.BoolVar(&o.EnableIngress, "enable-ingress", util.Env("ROUTER_ENABLE_INGRESS", "") == "true", "Enable ingress resource configuration of the router")
9193
}
9294

9395
type RouterStats struct {
@@ -215,7 +217,7 @@ func (o *TemplateRouterOptions) Run() error {
215217
plugin := controller.NewHostAdmitter(uniqueHostPlugin, o.RouteAdmissionFunc(), o.RestrictSubdomainOwnership, controller.RejectionRecorder(statusPlugin))
216218

217219
factory := o.RouterSelection.NewFactory(oc, kc)
218-
controller := factory.Create(plugin, false)
220+
controller := factory.Create(plugin, false, o.EnableIngress)
219221
controller.Run()
220222

221223
proc.StartReaper()

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

pkg/router/controller/controller.go

+113-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,8 @@ func (c *RouterController) Run() {
6377
if c.WatchNodes {
6478
go utilwait.Forever(c.HandleNode, 0)
6579
}
80+
go utilwait.Forever(c.HandleIngress, 0)
81+
go utilwait.Forever(c.HandleSecret, 0)
6682
go c.watchForFirstSync()
6783
}
6884

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

7591
synced := c.RoutesListSuccessfulAtLeastOnce() &&
7692
c.EndpointsListSuccessfulAtLeastOnce() &&
77-
(c.Namespaces == nil || c.filteredByNamespace)
93+
(c.Namespaces == nil || c.filteredByNamespace) &&
94+
(!c.EnableIngress ||
95+
(c.IngressesListSuccessfulAtLeastOnce() && c.SecretsListSuccessfulAtLeastOnce()))
7896
if !synced {
7997
return false
8098
}
8199

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.
100+
// If any of the event queues were empty after the initial List,
101+
// the tracking listConsumed variable's default value of 'false'
102+
// may prevent the router from committing. Set the value to
103+
// 'true' to ensure that state can be committed if necessary.
87104
if c.RoutesListCount() == 0 {
88105
c.routesListConsumed = true
89106
}
90107
if c.EndpointsListCount() == 0 {
91108
c.endpointsListConsumed = true
92109
}
110+
if c.EnableIngress {
111+
if c.IngressesListCount() == 0 {
112+
c.ingressesListConsumed = true
113+
}
114+
if c.SecretsListCount() == 0 {
115+
c.secretsListConsumed = true
116+
}
117+
}
93118
c.commit()
94119

95120
return true
@@ -109,6 +134,14 @@ func (c *RouterController) HandleNamespaces() {
109134
for i := 0; i < c.NamespaceRetries; i++ {
110135
namespaces, err := c.Namespaces.NamespaceNames()
111136
if err == nil {
137+
138+
// The ingress translator synchronizes access to its cache with a
139+
// lock, so calls to it are made outside of the controller lock to
140+
// avoid unintended interaction.
141+
if c.EnableIngress {
142+
c.IngressTranslator.UpdateNamespaces(namespaces)
143+
}
144+
112145
c.lock.Lock()
113146
defer c.lock.Unlock()
114147

@@ -161,13 +194,7 @@ func (c *RouterController) HandleRoute() {
161194
c.lock.Lock()
162195
defer c.lock.Unlock()
163196

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-
}
197+
c.processRoute(eventType, route)
171198

172199
// Change the local sync state within the lock to ensure that all
173200
// event handlers have the same view of sync state.
@@ -196,10 +223,61 @@ func (c *RouterController) HandleEndpoints() {
196223
c.commit()
197224
}
198225

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

0 commit comments

Comments
 (0)