-
Couldn't load subscription status.
- Fork 504
Update default backend behavior and strip host ports #1607
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,17 +14,11 @@ case class IngressSpec( | |
| ) { | ||
| def getMatchingPath(hostHeader: Option[String], requestPath: String): Option[IngressPath] = { | ||
| val matchingPath = rules.find(_.matches(hostHeader, requestPath)) | ||
| (matchingPath, fallbackBackend) match { | ||
| case (Some(path), _) => | ||
| log.info("k8s found rule matching %s %s: %s", hostHeader.getOrElse(""), requestPath, path) | ||
| Some(path) | ||
| case (None, Some(default)) => | ||
| log.info("k8s using default service %s for request %s %s", default, hostHeader.getOrElse(""), requestPath) | ||
| Some(default) | ||
| case _ => | ||
| log.info("k8s no suitable rule found in %s for request %s %s", name.getOrElse(""), hostHeader.getOrElse(""), requestPath) | ||
| None | ||
| matchingPath match { | ||
| case Some(path) => log.info("k8s found rule matching %s %s: %s", hostHeader.getOrElse(""), requestPath, path) | ||
| case None => log.info("no ingress rule found for request %s %s", hostHeader.getOrElse(""), requestPath) | ||
| } | ||
| matchingPath | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -59,13 +53,17 @@ object IngressCache { | |
| type IngressState = Activity.State[Seq[IngressSpec]] | ||
| val annotationKey = "kubernetes.io/ingress.class" | ||
|
|
||
| private[k8s] def getMatchingPath(hostHeader: Option[String], requestPath: String, ingresses: Seq[IngressSpec]): Option[IngressPath] = | ||
| private[k8s] def iterateForMatch(ingresses: Seq[IngressSpec], fn: (IngressSpec) => Option[IngressPath]) = | ||
| ingresses | ||
| .toIterator // stop after we find a match | ||
| .flatMap(_.getMatchingPath(hostHeader, requestPath)) | ||
| .flatMap(fn(_)) | ||
| .take(1) | ||
| .toSeq.headOption | ||
|
|
||
| private[k8s] def getMatchingPath(hostHeader: Option[String], requestPath: String, ingresses: Seq[IngressSpec]): Option[IngressPath] = | ||
| iterateForMatch(ingresses, _.getMatchingPath(hostHeader, requestPath)) | ||
| .orElse(iterateForMatch(ingresses, _.fallbackBackend)) | ||
|
|
||
| } | ||
|
|
||
| /** | ||
|
|
@@ -143,8 +141,16 @@ class IngressCache(namespace: Option[String], apiClient: Service[Request, Respon | |
| } | ||
| } | ||
|
|
||
| def matchPath(hostHeader: Option[String], requestPath: String): Future[Option[IngressPath]] = | ||
| def matchPath(hostHeader: Option[String], requestPath: String): Future[Option[IngressPath]] = { | ||
| val hostHeaderSansPort = hostHeader.map { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Peut-être "without" au lieu de "sans" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :) 🇫🇷 |
||
| _.split(":") match { | ||
| case Array(h: String, _) => h | ||
| case Array(h: String) => h | ||
| case _ => throw new IllegalArgumentException("unable to parse host for request") | ||
| } | ||
| } | ||
| ingresses.map { cache: Seq[IngressSpec] => | ||
| getMatchingPath(hostHeader, requestPath, cache) | ||
| getMatchingPath(hostHeaderSansPort, requestPath, cache) | ||
| }.toFuture | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -329,6 +329,12 @@ class IngressCacheTest extends FunSuite with Awaits { | |
| assert(await(cache.matchPath(host, "/non-existing-path")).isEmpty) | ||
| } | ||
|
|
||
| test("ignores port in a request's hostname") { | ||
| val service = mkIngressApiServiceReturning(ingressResourceListWithOneIngress) | ||
| val cache = new IngressCache(None, service, annotationClass) | ||
| assert(await(cache.matchPath(Some("myhost:80"), "/some-path")).get.svc == "echo") | ||
| } | ||
|
|
||
| test("on multiple path matches, return first match") { | ||
| val paths = Seq( | ||
| IngressPath(host, Some("/path"), ns.get, "primary-svc", "80"), | ||
|
|
@@ -346,6 +352,37 @@ class IngressCacheTest extends FunSuite with Awaits { | |
| assert(matchingPath.get.svc == "svc1") | ||
| } | ||
|
|
||
| test("don't return default backend before checking all resources for matches") { | ||
| val resource1 = IngressSpec( | ||
| Some("polar-bear1"), | ||
| ns, | ||
| Some(IngressPath(None, None, ns.get, "fallback", "80")), | ||
| Seq(IngressPath(Some("other host"), None, ns.get, "svc1", "80")) | ||
| ) | ||
| val resource2 = IngressSpec(Some("polar-bear2"), ns, None, Seq(IngressPath(host, None, ns.get, "svc2", "80"))) | ||
| val matchingPath = IngressCache.getMatchingPath(host, "/path", Seq(resource1, resource2)) | ||
| assert(matchingPath.get.svc == "svc2") | ||
| } | ||
|
|
||
| test("on no host/path matches, return first default backend") { | ||
| val resource1 = IngressSpec(Some("polar-bear1"), ns, None, Seq(IngressPath(host, None, ns.get, "svc1", "80"))) | ||
| val resource2 = IngressSpec( | ||
| Some("polar-bear2"), | ||
| ns, | ||
| Some(IngressPath(None, None, ns.get, "fallback", "80")), | ||
| Seq(IngressPath(host, None, ns.get, "svc2", "80")) | ||
| ) | ||
| val matchingPath = IngressCache.getMatchingPath(Some("unknown host"), "/path", Seq(resource1, resource2)) | ||
| assert(matchingPath.get.svc == "fallback") | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we consider the case where no default backend exists? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure! I will add a test |
||
| test("no matches") { | ||
| val resource1 = IngressSpec(Some("polar-bear1"), ns, None, Seq(IngressPath(host, None, ns.get, "svc1", "80"))) | ||
| val resource2 = IngressSpec(Some("polar-bear2"), ns, None, Seq(IngressPath(host, None, ns.get, "svc2", "80"))) | ||
| val matchingPath = IngressCache.getMatchingPath(Some("unknown host"), "/path", Seq(resource1, resource2)) | ||
| assert(matchingPath == None) | ||
| } | ||
|
|
||
| test("match on path regex") { | ||
| val path = IngressPath(host, Some("/prefix/.*"), ns.get, "svc1", "80") | ||
| assert(path.matches(host, "/prefix/and-other-stuff")) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I might be missing something, but is this basically the same as Iterator#find()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you, not sure why I'm tiptoeing around
toIteratorlike a sacred cowUh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh figured it out, we need to return the path that matches, not the whole matching spec. We could do it in 2 phases, but we'd like to be as efficient as possible on the request path.