forked from linkerd/linkerd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SubnetGatewayTransformer.scala
86 lines (76 loc) · 2.97 KB
/
SubnetGatewayTransformer.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package io.buoyant.transformer
import com.twitter.finagle.Name.Bound
import com.twitter.finagle._
import com.twitter.finagle.naming.NameInterpreter
import com.twitter.util.{Activity, Future, Var}
import io.buoyant.admin.Admin
import io.buoyant.namer.{DelegateTree, DelegatingNameTreeTransformer, RichActivity}
/**
* Transforms a bound name tree to only include addresses in
* `gatewayTree` that are in the same subnet of the original address.
*/
class SubnetGatewayTransformer(
prefix: Path,
gatewayTree: Activity[NameTree[Bound]],
netmask: Netmask,
handlers: Seq[Admin.Handler] = Seq.empty
) extends GatewayTransformer(prefix, gatewayTree, netmask.local, handlers)
class MetadataGatewayTransformer(
prefix: Path,
gatewayTree: Activity[NameTree[Bound]],
metadataField: String,
handlers: Seq[Admin.Handler] = Seq.empty
) extends GatewayTransformer(prefix, gatewayTree, {
case (Address.Inet(_, a), Address.Inet(_, b)) => a.get(metadataField) == b.get(metadataField)
case _ => true
},
handlers)
class GatewayTransformer(
prefix: Path,
gatewayTree: Activity[NameTree[Bound]],
gatewayPredicate: (Address, Address) => Boolean,
handlers: Seq[Admin.Handler] = Seq.empty
) extends DelegatingNameTreeTransformer with Admin.WithHandlers {
override def adminHandlers: Seq[Admin.Handler] = handlers
override protected def transformDelegate(tree: DelegateTree[Bound]): Future[DelegateTree[Bound]] =
gatewayTree.toFuture.map { gateways =>
val routable = flatten(gateways.eval.toSet.flatten)
DelegatingNameTreeTransformer.transformDelegate(tree, mapBound(_, routable))
}
override protected def transform(tree: NameTree[Bound]): Activity[NameTree[Bound]] =
gatewayTree.map { gateways =>
val routable = flatten(gateways.eval.toSet.flatten)
tree.map(mapBound(_, routable))
}
/** Smoosh together all of the bound addresses into a single Var */
private[this] def flatten(bounds: Set[Name.Bound]): Var[Addr] =
Var.collect(bounds.map(_.addr)).map { addrs =>
val collectedAddresses = addrs.flatMap {
case Addr.Bound(addresses, _) => addresses
case _ => Set.empty[Address]
}
Addr.Bound(collectedAddresses)
}
/**
* Return a new Bound with the address replaced by a member of the
* set of gateways ont he same subnet.
*/
private[this] def mapBound(bound: Name.Bound, gateway: Var[Addr]): Name.Bound = {
val vaddr = Var.collect(List(bound.addr, gateway)).map {
case List(Addr.Bound(addrs, meta), Addr.Bound(gatewayAddrs, _)) =>
val selected = addrs.flatMap { addr =>
// select the gateway addresses that share a subnet with addr
gatewayAddrs.filter(gatewayPredicate(addr, _))
}
if (selected.isEmpty)
Addr.Neg
else
Addr.Bound(selected, meta)
case List(addr, _) => addr
}
bound.id match {
case id: Path => Name.Bound(vaddr, prefix ++ id, bound.path)
case _ => Name.Bound(vaddr, bound.id, bound.path)
}
}
}