Skip to content

Commit

Permalink
Fix k8s namer to handle null ep subsets (#1219) (#1223)
Browse files Browse the repository at this point in the history
In Kubernetes 1.6.1, the EndpointsList API changed so that the `subsets`
field may be null.

To resolve this, subsets have been made optional.

A test case has been added to validate this.

Fixes #1219
  • Loading branch information
siggy committed Apr 19, 2017
1 parent 21467a8 commit 214cfb1
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -13,6 +13,7 @@
* Add support for per-service configuration.
* Split the timeoutMs router option into a requestAttemptTimeoutMs client option
and a totalTimeoutMs service option.
* Fixed k8s namer to handle null endpoint subsets.

## 0.9.1 2017-03-15

Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Expand Up @@ -44,6 +44,8 @@ Problem
Solution
Validation
Fixes #[Github issue ID]
```

#### Subject ####
Expand Down
10 changes: 5 additions & 5 deletions k8s/src/main/scala/io/buoyant/k8s/EndpointsNamer.scala
Expand Up @@ -120,10 +120,10 @@ private object EndpointsNamer {

case class Svc(endpoints: Set[Endpoint], ports: Map[String, Int])

private[this] def getEndpoints(subsets: Seq[v1.EndpointSubset]): Set[Endpoint] = {
private[this] def getEndpoints(subsets: Option[Seq[v1.EndpointSubset]]): Set[Endpoint] = {
val endpoints = mutable.Set.empty[Endpoint]
for {
subset <- subsets
subset <- subsets.getOrElse(Seq.empty)
addresses <- subset.addresses
addrs <- addresses
} {
Expand All @@ -132,10 +132,10 @@ private object EndpointsNamer {
endpoints.toSet
}

private[this] def getPorts(subsets: Seq[v1.EndpointSubset]): Map[String, Int] = {
private[this] def getPorts(subsets: Option[Seq[v1.EndpointSubset]]): Map[String, Int] = {
val portSet = mutable.Map.empty[String, Int]
for {
subset <- subsets
subset <- subsets.getOrElse(Seq.empty)
ports <- subset.ports
port <- ports
name <- port.name
Expand Down Expand Up @@ -171,7 +171,7 @@ private object EndpointsNamer {

def ports: Var[Map[String, Int]] = portsState

def update(subsets: Seq[v1.EndpointSubset]): Unit = {
def update(subsets: Option[Seq[v1.EndpointSubset]]): Unit = {
val newEndpoints = getEndpoints(subsets)
val newPorts = getPorts(subsets)

Expand Down
2 changes: 1 addition & 1 deletion k8s/src/main/scala/io/buoyant/k8s/v1.scala
Expand Up @@ -101,7 +101,7 @@ package object v1 {
) extends KubeList[Endpoints]

case class Endpoints(
subsets: Seq[EndpointSubset],
subsets: Option[Seq[EndpointSubset]] = None,
kind: Option[String] = None,
metadata: Option[ObjectMeta] = None,
apiVersion: Option[String] = None
Expand Down
13 changes: 12 additions & 1 deletion k8s/src/test/scala/io/buoyant/k8s/EndpointsNamerTest.scala
Expand Up @@ -14,7 +14,7 @@ class EndpointsNamerTest extends FunSuite with Awaits {

object Rsps {

val Init = Buf.Utf8("""{"kind":"EndpointsList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/srv/endpoints","resourceVersion":"5319481"},"items":[{"metadata":{"name":"accounts","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/accounts","uid":"6b4f8411-525e-11e5-9859-42010af01815","resourceVersion":"4969550","creationTimestamp":"2015-09-03T17:08:38Z"},"subsets":[{"addresses":[{"ip":"10.248.2.10","targetRef":{"kind":"Pod","namespace":"srv","name":"accounts-wl3n0","uid":"6ada6391-525e-11e5-9859-42010af01815","resourceVersion":"4962571"}},{"ip":"10.248.4.10","targetRef":{"kind":"Pod","namespace":"srv","name":"accounts-bbukv","uid":"6ada5545-525e-11e5-9859-42010af01815","resourceVersion":"4962603"}},{"ip":"10.248.5.10","targetRef":{"kind":"Pod","namespace":"srv","name":"accounts-3zbq3","uid":"6ada42a6-525e-11e5-9859-42010af01815","resourceVersion":"4962601"}}],"ports":[{"name":"http","port":8086,"protocol":"TCP"}]}]},{"metadata":{"name":"auth","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/auth","uid":"6982a2fc-525e-11e5-9859-42010af01815","resourceVersion":"4969546","creationTimestamp":"2015-09-03T17:08:35Z"},"subsets":[{"addresses":[{"ip":"10.248.0.10","targetRef":{"kind":"Pod","namespace":"srv","name":"auth-vmcia","uid":"690ef84c-525e-11e5-9859-42010af01815","resourceVersion":"4962519"}},{"ip":"10.248.1.9","targetRef":{"kind":"Pod","namespace":"srv","name":"auth-d8qnl","uid":"690f06c8-525e-11e5-9859-42010af01815","resourceVersion":"4962570"}},{"ip":"10.248.5.9","targetRef":{"kind":"Pod","namespace":"srv","name":"auth-m79ya","uid":"690f05df-525e-11e5-9859-42010af01815","resourceVersion":"4962464"}}],"ports":[{"name":"http","port":8082,"protocol":"TCP"}]}]},{"metadata":{"name":"events","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/events","uid":"67abfc86-525e-11e5-9859-42010af01815","resourceVersion":"4962380","creationTimestamp":"2015-09-03T17:08:32Z"},"subsets":[{"addresses":[{"ip":"10.248.0.9","targetRef":{"kind":"Pod","namespace":"srv","name":"events-6g3in","uid":"673a6ebf-525e-11e5-9859-42010af01815","resourceVersion":"4962378"}},{"ip":"10.248.5.8","targetRef":{"kind":"Pod","namespace":"srv","name":"events-l8xyq","uid":"673a68fe-525e-11e5-9859-42010af01815","resourceVersion":"4962374"}},{"ip":"10.248.6.8","targetRef":{"kind":"Pod","namespace":"srv","name":"events-4hkt8","uid":"673a664a-525e-11e5-9859-42010af01815","resourceVersion":"4962350"}}],"ports":[{"name":"http","port":8085,"protocol":"TCP"}]}]},{"metadata":{"name":"projects","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/projects","uid":"6c39393c-525e-11e5-9859-42010af01815","resourceVersion":"4962611","creationTimestamp":"2015-09-03T17:08:40Z"},"subsets":[{"addresses":[{"ip":"10.248.0.11","targetRef":{"kind":"Pod","namespace":"srv","name":"projects-h2zbp","uid":"6bc6a899-525e-11e5-9859-42010af01815","resourceVersion":"4962606"}},{"ip":"10.248.7.12","targetRef":{"kind":"Pod","namespace":"srv","name":"projects-fzfv2","uid":"6bc6b7be-525e-11e5-9859-42010af01815","resourceVersion":"4962607"}},{"ip":"10.248.8.10","targetRef":{"kind":"Pod","namespace":"srv","name":"projects-0o69j","uid":"6bc6c27c-525e-11e5-9859-42010af01815","resourceVersion":"4962610"}}],"ports":[{"name":"http","port":8087,"protocol":"TCP"}]}]},{"metadata":{"name":"sessions","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/sessions","uid":"6a698096-525e-11e5-9859-42010af01815","resourceVersion":"4962526","creationTimestamp":"2015-09-03T17:08:37Z"},"subsets":[{"addresses":[{"ip":"10.248.4.9","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-293kc","uid":"69f5a7d2-525e-11e5-9859-42010af01815","resourceVersion":"4962471"}},{"ip":"10.248.7.11","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-mr9gb","uid":"69f5b78e-525e-11e5-9859-42010af01815","resourceVersion":"4962524"}},{"ip":"10.248.8.9","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-nicom","uid":"69f5b623-525e-11e5-9859-42010af01815","resourceVersion":"4962517"}}],"ports":[{"name":"http","port":8083,"protocol":"TCP"}]}]},{"metadata":{"name":"users","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/users","uid":"689a2ff3-525e-11e5-9859-42010af01815","resourceVersion":"4962565","creationTimestamp":"2015-09-03T17:08:34Z"},"subsets":[{"addresses":[{"ip":"10.248.2.9","targetRef":{"kind":"Pod","namespace":"srv","name":"users-o8vvr","uid":"681d409e-525e-11e5-9859-42010af01815","resourceVersion":"4962462"}},{"ip":"10.248.4.8","targetRef":{"kind":"Pod","namespace":"srv","name":"users-u3lnj","uid":"681d31f2-525e-11e5-9859-42010af01815","resourceVersion":"4962422"}},{"ip":"10.248.6.9","targetRef":{"kind":"Pod","namespace":"srv","name":"users-m3fmq","uid":"681d3fa6-525e-11e5-9859-42010af01815","resourceVersion":"4962564"}}],"ports":[{"name":"http","port":8081,"protocol":"TCP"}]}]},{"metadata":{"name":"web","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/web","uid":"6d5bd683-525e-11e5-9859-42010af01815","resourceVersion":"4962619","creationTimestamp":"2015-09-03T17:08:41Z"},"subsets":[{"addresses":[{"ip":"10.248.1.10","targetRef":{"kind":"Pod","namespace":"srv","name":"web-9n3g9","uid":"6ceacdf3-525e-11e5-9859-42010af01815","resourceVersion":"4962617"}},{"ip":"10.248.2.11","targetRef":{"kind":"Pod","namespace":"srv","name":"web-2o0ut","uid":"6ceacd0d-525e-11e5-9859-42010af01815","resourceVersion":"4962616"}},{"ip":"10.248.6.10","targetRef":{"kind":"Pod","namespace":"srv","name":"web-hxz7q","uid":"6ceabb69-525e-11e5-9859-42010af01815","resourceVersion":"4962614"}}],"ports":[{"name":"http","port":8084,"protocol":"TCP"}]}]}]}""")
val Init = Buf.Utf8("""{"kind": "EndpointsList","apiVersion": "v1","metadata": {"selfLink": "/api/v1/namespaces/srv/endpoints","resourceVersion": "5319481"},"items": [{"metadata": {"name": "accounts","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/accounts","uid": "6b4f8411-525e-11e5-9859-42010af01815","resourceVersion": "4969550","creationTimestamp": "2015-09-03T17:08:38Z"},"subsets": [{"addresses": [{"ip": "10.248.2.10","targetRef": {"kind": "Pod","namespace": "srv","name": "accounts-wl3n0","uid": "6ada6391-525e-11e5-9859-42010af01815","resourceVersion": "4962571"}},{"ip": "10.248.4.10","targetRef": {"kind": "Pod","namespace": "srv","name": "accounts-bbukv","uid": "6ada5545-525e-11e5-9859-42010af01815","resourceVersion": "4962603"}},{"ip": "10.248.5.10","targetRef": {"kind": "Pod","namespace": "srv","name": "accounts-3zbq3","uid": "6ada42a6-525e-11e5-9859-42010af01815","resourceVersion": "4962601"}}],"ports": [{"name": "http","port": 8086,"protocol": "TCP"}]}]},{"metadata": {"name": "auth","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/auth","uid": "6982a2fc-525e-11e5-9859-42010af01815","resourceVersion": "4969546","creationTimestamp": "2015-09-03T17:08:35Z"},"subsets": [{"addresses": [{"ip": "10.248.0.10","targetRef": {"kind": "Pod","namespace": "srv","name": "auth-vmcia","uid": "690ef84c-525e-11e5-9859-42010af01815","resourceVersion": "4962519"}},{"ip": "10.248.1.9","targetRef": {"kind": "Pod","namespace": "srv","name": "auth-d8qnl","uid": "690f06c8-525e-11e5-9859-42010af01815","resourceVersion": "4962570"}},{"ip": "10.248.5.9","targetRef": {"kind": "Pod","namespace": "srv","name": "auth-m79ya","uid": "690f05df-525e-11e5-9859-42010af01815","resourceVersion": "4962464"}}],"ports": [{"name": "http","port": 8082,"protocol": "TCP"}]}]},{"metadata": {"name": "events","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/events","uid": "67abfc86-525e-11e5-9859-42010af01815","resourceVersion": "4962380","creationTimestamp": "2015-09-03T17:08:32Z"},"subsets": [{"addresses": [{"ip": "10.248.0.9","targetRef": {"kind": "Pod","namespace": "srv","name": "events-6g3in","uid": "673a6ebf-525e-11e5-9859-42010af01815","resourceVersion": "4962378"}},{"ip": "10.248.5.8","targetRef": {"kind": "Pod","namespace": "srv","name": "events-l8xyq","uid": "673a68fe-525e-11e5-9859-42010af01815","resourceVersion": "4962374"}},{"ip": "10.248.6.8","targetRef": {"kind": "Pod","namespace": "srv","name": "events-4hkt8","uid": "673a664a-525e-11e5-9859-42010af01815","resourceVersion": "4962350"}}],"ports": [{"name": "http","port": 8085,"protocol": "TCP"}]}]},{"metadata": {"name": "projects","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/projects","uid": "6c39393c-525e-11e5-9859-42010af01815","resourceVersion": "4962611","creationTimestamp": "2015-09-03T17:08:40Z"},"subsets": [{"addresses": [{"ip": "10.248.0.11","targetRef": {"kind": "Pod","namespace": "srv","name": "projects-h2zbp","uid": "6bc6a899-525e-11e5-9859-42010af01815","resourceVersion": "4962606"}},{"ip": "10.248.7.12","targetRef": {"kind": "Pod","namespace": "srv","name": "projects-fzfv2","uid": "6bc6b7be-525e-11e5-9859-42010af01815","resourceVersion": "4962607"}},{"ip": "10.248.8.10","targetRef": {"kind": "Pod","namespace": "srv","name": "projects-0o69j","uid": "6bc6c27c-525e-11e5-9859-42010af01815","resourceVersion": "4962610"}}],"ports": [{"name": "http","port": 8087,"protocol": "TCP"}]}]},{"metadata": {"name": "sessions","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/sessions","uid": "6a698096-525e-11e5-9859-42010af01815","resourceVersion": "4962526","creationTimestamp": "2015-09-03T17:08:37Z"},"subsets": [{"addresses": [{"ip": "10.248.4.9","targetRef": {"kind": "Pod","namespace": "srv","name": "sessions-293kc","uid": "69f5a7d2-525e-11e5-9859-42010af01815","resourceVersion": "4962471"}},{"ip": "10.248.7.11","targetRef": {"kind": "Pod","namespace": "srv","name": "sessions-mr9gb","uid": "69f5b78e-525e-11e5-9859-42010af01815","resourceVersion": "4962524"}},{"ip": "10.248.8.9","targetRef": {"kind": "Pod","namespace": "srv","name": "sessions-nicom","uid": "69f5b623-525e-11e5-9859-42010af01815","resourceVersion": "4962517"}}],"ports": [{"name": "http","port": 8083,"protocol": "TCP"}]}]},{"metadata": {"name": "users","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/users","uid": "689a2ff3-525e-11e5-9859-42010af01815","resourceVersion": "4962565","creationTimestamp": "2015-09-03T17:08:34Z"},"subsets": [{"addresses": [{"ip": "10.248.2.9","targetRef": {"kind": "Pod","namespace": "srv","name": "users-o8vvr","uid": "681d409e-525e-11e5-9859-42010af01815","resourceVersion": "4962462"}},{"ip": "10.248.4.8","targetRef": {"kind": "Pod","namespace": "srv","name": "users-u3lnj","uid": "681d31f2-525e-11e5-9859-42010af01815","resourceVersion": "4962422"}},{"ip": "10.248.6.9","targetRef": {"kind": "Pod","namespace": "srv","name": "users-m3fmq","uid": "681d3fa6-525e-11e5-9859-42010af01815","resourceVersion": "4962564"}}],"ports": [{"name": "http","port": 8081,"protocol": "TCP"}]}]},{"metadata": {"name": "web","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/web","uid": "6d5bd683-525e-11e5-9859-42010af01815","resourceVersion": "4962619","creationTimestamp": "2015-09-03T17:08:41Z"},"subsets": [{"addresses": [{"ip": "10.248.1.10","targetRef": {"kind": "Pod","namespace": "srv","name": "web-9n3g9","uid": "6ceacdf3-525e-11e5-9859-42010af01815","resourceVersion": "4962617"}},{"ip": "10.248.2.11","targetRef": {"kind": "Pod","namespace": "srv","name": "web-2o0ut","uid": "6ceacd0d-525e-11e5-9859-42010af01815","resourceVersion": "4962616"}},{"ip": "10.248.6.10","targetRef": {"kind": "Pod","namespace": "srv","name": "web-hxz7q","uid": "6ceabb69-525e-11e5-9859-42010af01815","resourceVersion": "4962614"}}],"ports": [{"name": "http","port": 8084,"protocol": "TCP"}]}]},{"metadata": {"name": "empty-subset","namespace": "srv","selfLink": "/api/v1/namespaces/srv/endpoints/empty-subset","uid": "7d5bd683-525e-11e5-9859-42010af01815","resourceVersion": "5962619","creationTimestamp": "2016-09-03T17:08:41Z"},"subsets": null}]}""")

val ScaleUp = Buf.Utf8("""{"type":"MODIFIED","object":{"kind":"Endpoints","apiVersion":"v1","metadata":{"name":"sessions","namespace":"srv","selfLink":"/api/v1/namespaces/srv/endpoints/sessions","uid":"6a698096-525e-11e5-9859-42010af01815","resourceVersion":"5319582","creationTimestamp":"2015-09-03T17:08:37Z"},"subsets":[{"addresses":[{"ip":"10.248.1.11","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-09ujq","uid":"669b7a4f-55ef-11e5-a801-42010af08a01","resourceVersion":"5319581"}},{"ip":"10.248.4.9","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-293kc","uid":"69f5a7d2-525e-11e5-9859-42010af01815","resourceVersion":"4962471"}},{"ip":"10.248.7.11","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-mr9gb","uid":"69f5b78e-525e-11e5-9859-42010af01815","resourceVersion":"4962524"}},{"ip":"10.248.8.9","targetRef":{"kind":"Pod","namespace":"srv","name":"sessions-nicom","uid":"69f5b623-525e-11e5-9859-42010af01815","resourceVersion":"4962517"}}],"ports":[{"name":"http","port":8083,"protocol":"TCP"}]}]}}""")

Expand Down Expand Up @@ -216,4 +216,15 @@ class EndpointsNamerTest extends FunSuite with Awaits {
assertHas(3)
}
}

test("namer handles endpoints will null subsets") {
val _ = new Fixtures {
override def name = "/srv/http/empty-subset"

assert(state == Activity.Pending)
doInit.setDone()

assert(state == Activity.Ok(NameTree.Neg))
}
}
}

0 comments on commit 214cfb1

Please sign in to comment.