Merge pull request #3 from p2p-org/support_grpc_labels
Support gRPC upstream labels
This commit is contained in:
@@ -829,6 +829,8 @@ It's more effective, easier to secure connection, and allows to build a distribu
|
|||||||
[source,yaml]
|
[source,yaml]
|
||||||
----
|
----
|
||||||
- id: test1
|
- id: test1
|
||||||
|
labels:
|
||||||
|
provider: some
|
||||||
connection:
|
connection:
|
||||||
grpc:
|
grpc:
|
||||||
host: eu-api.mycompany.com
|
host: eu-api.mycompany.com
|
||||||
@@ -848,6 +850,10 @@ It's more effective, easier to secure connection, and allows to build a distribu
|
|||||||
| yes
|
| yes
|
||||||
| Per-cluster identifier of an upstream
|
| Per-cluster identifier of an upstream
|
||||||
|
|
||||||
|
| `labels`
|
||||||
|
| no
|
||||||
|
| Defines the labels can be used for the proper upstream instance selection. Overrides the labels retrieved by the `describe` method
|
||||||
|
|
||||||
| `connection.grpc`
|
| `connection.grpc`
|
||||||
| yes
|
| yes
|
||||||
| Connection configuration for Dshackle gRPC
|
| Connection configuration for Dshackle gRPC
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import io.emeraldpay.dshackle.FileResolver
|
|||||||
import org.apache.commons.lang3.StringUtils
|
import org.apache.commons.lang3.StringUtils
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.yaml.snakeyaml.nodes.MappingNode
|
import org.yaml.snakeyaml.nodes.MappingNode
|
||||||
import org.yaml.snakeyaml.nodes.ScalarNode
|
|
||||||
import reactor.util.function.Tuples
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@@ -83,7 +81,7 @@ class UpstreamsConfigReader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getList<MappingNode>(input, "upstreams")?.value?.forEachIndexed { _, upNode ->
|
getList<MappingNode>(input, "upstreams")?.value?.forEach { upNode ->
|
||||||
val connNode = getMapping(upNode, "connection")
|
val connNode = getMapping(upNode, "connection")
|
||||||
if (hasAny(connNode, "ethereum")) {
|
if (hasAny(connNode, "ethereum")) {
|
||||||
readUpstream(config, upNode) {
|
readUpstream(config, upNode) {
|
||||||
@@ -211,7 +209,11 @@ class UpstreamsConfigReader(
|
|||||||
return connection
|
return connection
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : UpstreamsConfig.UpstreamConnection> readUpstream(config: UpstreamsConfig, upNode: MappingNode, connFactory: () -> T) {
|
private fun <T : UpstreamsConfig.UpstreamConnection> readUpstream(
|
||||||
|
config: UpstreamsConfig,
|
||||||
|
upNode: MappingNode,
|
||||||
|
connFactory: () -> T
|
||||||
|
) {
|
||||||
val upstream = UpstreamsConfig.Upstream<T>()
|
val upstream = UpstreamsConfig.Upstream<T>()
|
||||||
readUpstreamCommon(upNode, upstream)
|
readUpstreamCommon(upNode, upstream)
|
||||||
readUpstreamStandard(upNode, upstream)
|
readUpstreamStandard(upNode, upstream)
|
||||||
@@ -241,18 +243,21 @@ class UpstreamsConfigReader(
|
|||||||
getValueAsBool(upNode, "enabled")?.let {
|
getValueAsBool(upNode, "enabled")?.let {
|
||||||
upstream.isEnabled = it
|
upstream.isEnabled = it
|
||||||
}
|
}
|
||||||
|
if (hasAny(upNode, "labels")) {
|
||||||
|
getMapping(upNode, "labels")?.let { labels ->
|
||||||
|
labels.value.stream()
|
||||||
|
.map { it.keyNode.valueAsString() to it.valueNode.valueAsString() }
|
||||||
|
.filter { StringUtils.isNotBlank(it.first) && StringUtils.isNotBlank(it.second) }
|
||||||
|
.forEach {
|
||||||
|
upstream.labels[it.first!!.trim()] = it.second!!.trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun readUpstreamGrpc(
|
internal fun readUpstreamGrpc(
|
||||||
upNode: MappingNode,
|
upNode: MappingNode,
|
||||||
) {
|
) {
|
||||||
// Dshackle gRPC connection dispatches requests to different upstreams, which may
|
|
||||||
// be on different blockchains, and each may have different set of labels.
|
|
||||||
// So the labels and chains assigned to the gRPC connection make no sense.
|
|
||||||
if (hasAny(upNode, "labels")) {
|
|
||||||
// Actual labels from underlying upstreams are handled by GrpcUpstreamStatus
|
|
||||||
log.warn("Labels should be not applied to gRPC upstream")
|
|
||||||
}
|
|
||||||
if (hasAny(upNode, "chain")) {
|
if (hasAny(upNode, "chain")) {
|
||||||
log.warn("Chain should be not applied to gRPC upstream")
|
log.warn("Chain should be not applied to gRPC upstream")
|
||||||
}
|
}
|
||||||
@@ -272,18 +277,6 @@ class UpstreamsConfigReader(
|
|||||||
log.warn("Unsupported role `$name` for upstream ${upstream.id}")
|
log.warn("Unsupported role `$name` for upstream ${upstream.id}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAny(upNode, "labels")) {
|
|
||||||
getMapping(upNode, "labels")?.let { labels ->
|
|
||||||
labels.value.stream()
|
|
||||||
.filter { n -> n.keyNode is ScalarNode && n.valueNode is ScalarNode }
|
|
||||||
.map { n -> Tuples.of((n.keyNode as ScalarNode).value, (n.valueNode as ScalarNode).value) }
|
|
||||||
.map { kv -> Tuples.of(kv.t1.trim(), kv.t2.trim()) }
|
|
||||||
.filter { kv -> StringUtils.isNotEmpty(kv.t1) && StringUtils.isNotEmpty(kv.t2) }
|
|
||||||
.forEach { kv ->
|
|
||||||
upstream.labels[kv.t1] = kv.t2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun tryReadOptions(upNode: MappingNode): UpstreamsConfig.Options? {
|
internal fun tryReadOptions(upNode: MappingNode): UpstreamsConfig.Options? {
|
||||||
|
|||||||
@@ -37,18 +37,12 @@ abstract class YamlConfigReader {
|
|||||||
return asMappingNode(yaml.compose(InputStreamReader(input)))
|
return asMappingNode(yaml.compose(InputStreamReader(input)))
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun hasAny(mappingNode: MappingNode?, key: String): Boolean {
|
protected fun hasAny(mappingNode: MappingNode?, key: String): Boolean =
|
||||||
if (mappingNode == null) {
|
mappingNode?.let { node ->
|
||||||
return false
|
node.value
|
||||||
}
|
.stream()
|
||||||
return mappingNode.value
|
.anyMatch { it.keyNode.valueAsString() == key }
|
||||||
.stream()
|
} ?: false
|
||||||
.filter { n -> n.keyNode is ScalarNode }
|
|
||||||
.filter { n ->
|
|
||||||
val sn = n.keyNode as ScalarNode
|
|
||||||
key == sn.value
|
|
||||||
}.count() > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun <T> getValue(mappingNode: MappingNode?, key: String, type: Class<T>): T? {
|
private fun <T> getValue(mappingNode: MappingNode?, key: String, type: Class<T>): T? {
|
||||||
@@ -57,21 +51,15 @@ abstract class YamlConfigReader {
|
|||||||
}
|
}
|
||||||
return mappingNode.value
|
return mappingNode.value
|
||||||
.stream()
|
.stream()
|
||||||
.filter { n -> n.keyNode is ScalarNode && type.isAssignableFrom(n.valueNode.javaClass) }
|
.filter { type.isAssignableFrom(it.valueNode.javaClass) }
|
||||||
.filter { n ->
|
.filter { it.keyNode.valueAsString() == key }
|
||||||
val sn = n.keyNode as ScalarNode
|
|
||||||
key == sn.value
|
|
||||||
}
|
|
||||||
.map { n -> n.valueNode as T }
|
.map { n -> n.valueNode as T }
|
||||||
.findFirst().let {
|
.findFirst()
|
||||||
if (it.isPresent) {
|
.orElse(null)
|
||||||
it.get()
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Node.valueAsString(): String? = if (this is ScalarNode) this.value else null
|
||||||
|
|
||||||
protected fun getMapping(mappingNode: MappingNode?, key: String): MappingNode? {
|
protected fun getMapping(mappingNode: MappingNode?, key: String): MappingNode? {
|
||||||
return getValue(mappingNode, key, MappingNode::class.java)
|
return getValue(mappingNode, key, MappingNode::class.java)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ open class ConfiguredUpstreams(
|
|||||||
endpoint.port,
|
endpoint.port,
|
||||||
endpoint.auth,
|
endpoint.auth,
|
||||||
fileResolver,
|
fileResolver,
|
||||||
endpoint.upstreamRating
|
endpoint.upstreamRating,
|
||||||
|
config.labels
|
||||||
).apply {
|
).apply {
|
||||||
timeout = options.timeout
|
timeout = options.timeout
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,7 @@ import io.emeraldpay.dshackle.upstream.forkchoice.ForkChoice
|
|||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcWsClient
|
||||||
import io.emeraldpay.dshackle.upstream.rpcclient.RpcMetrics
|
|
||||||
import io.emeraldpay.grpc.Chain
|
import io.emeraldpay.grpc.Chain
|
||||||
import io.micrometer.core.instrument.Counter
|
|
||||||
import io.micrometer.core.instrument.Metrics
|
|
||||||
import io.micrometer.core.instrument.Tag
|
|
||||||
import io.micrometer.core.instrument.Timer
|
|
||||||
|
|
||||||
class EthereumWsConnector(
|
class EthereumWsConnector(
|
||||||
wsFactory: EthereumWsFactory,
|
wsFactory: EthereumWsFactory,
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ class BitcoinGrpcUpstream(
|
|||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
chain: Chain,
|
chain: Chain,
|
||||||
val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
||||||
private val client: JsonRpcGrpcClient
|
private val client: JsonRpcGrpcClient,
|
||||||
|
overrideLabels: UpstreamsConfig.Labels?
|
||||||
) : BitcoinUpstream(
|
) : BitcoinUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
chain,
|
chain,
|
||||||
@@ -95,7 +96,7 @@ class BitcoinGrpcUpstream(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private val upstreamStatus = GrpcUpstreamStatus()
|
private val upstreamStatus = GrpcUpstreamStatus(overrideLabels)
|
||||||
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, MostWorkForkChoice())
|
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, MostWorkForkChoice())
|
||||||
var timeout = Defaults.timeout
|
var timeout = Defaults.timeout
|
||||||
private var capabilities: Set<Capability> = emptySet()
|
private var capabilities: Set<Capability> = emptySet()
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ open class EthereumGrpcUpstream(
|
|||||||
role: UpstreamsConfig.UpstreamRole,
|
role: UpstreamsConfig.UpstreamRole,
|
||||||
private val chain: Chain,
|
private val chain: Chain,
|
||||||
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
||||||
private val client: JsonRpcGrpcClient
|
private val client: JsonRpcGrpcClient,
|
||||||
|
overrideLabels: UpstreamsConfig.Labels?
|
||||||
) : EthereumUpstream(
|
) : EthereumUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
UpstreamsConfig.Options.getDefaults(),
|
UpstreamsConfig.Options.getDefaults(),
|
||||||
@@ -93,7 +94,7 @@ open class EthereumGrpcUpstream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(EthereumGrpcUpstream::class.java)
|
private val log = LoggerFactory.getLogger(EthereumGrpcUpstream::class.java)
|
||||||
private val upstreamStatus = GrpcUpstreamStatus()
|
private val upstreamStatus = GrpcUpstreamStatus(overrideLabels)
|
||||||
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, MostWorkForkChoice())
|
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, MostWorkForkChoice())
|
||||||
private var capabilities: Set<Capability> = emptySet()
|
private var capabilities: Set<Capability> = emptySet()
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,11 @@ import io.emeraldpay.dshackle.data.BlockContainer
|
|||||||
import io.emeraldpay.dshackle.data.BlockId
|
import io.emeraldpay.dshackle.data.BlockId
|
||||||
import io.emeraldpay.dshackle.reader.Reader
|
import io.emeraldpay.dshackle.reader.Reader
|
||||||
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
import io.emeraldpay.dshackle.startup.QuorumForLabels
|
||||||
import io.emeraldpay.dshackle.upstream.*
|
import io.emeraldpay.dshackle.upstream.Capability
|
||||||
|
import io.emeraldpay.dshackle.upstream.Head
|
||||||
|
import io.emeraldpay.dshackle.upstream.Selector
|
||||||
|
import io.emeraldpay.dshackle.upstream.Upstream
|
||||||
|
import io.emeraldpay.dshackle.upstream.UpstreamAvailability
|
||||||
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
import io.emeraldpay.dshackle.upstream.calls.CallMethods
|
||||||
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosUpstream
|
import io.emeraldpay.dshackle.upstream.ethereum.EthereumPosUpstream
|
||||||
import io.emeraldpay.dshackle.upstream.forkchoice.NoChoiceWithPriorityForkChoice
|
import io.emeraldpay.dshackle.upstream.forkchoice.NoChoiceWithPriorityForkChoice
|
||||||
@@ -50,7 +54,8 @@ open class EthereumPosGrpcUpstream(
|
|||||||
private val chain: Chain,
|
private val chain: Chain,
|
||||||
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
private val remote: ReactorBlockchainGrpc.ReactorBlockchainStub,
|
||||||
client: JsonRpcGrpcClient,
|
client: JsonRpcGrpcClient,
|
||||||
nodeRating: Int
|
nodeRating: Int,
|
||||||
|
overrideLabels: UpstreamsConfig.Labels?
|
||||||
) : EthereumPosUpstream(
|
) : EthereumPosUpstream(
|
||||||
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
"${parentId}_${chain.chainCode.lowercase(Locale.getDefault())}",
|
||||||
UpstreamsConfig.Options.getDefaults(),
|
UpstreamsConfig.Options.getDefaults(),
|
||||||
@@ -94,7 +99,7 @@ open class EthereumPosGrpcUpstream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(EthereumGrpcUpstream::class.java)
|
private val log = LoggerFactory.getLogger(EthereumGrpcUpstream::class.java)
|
||||||
private val upstreamStatus = GrpcUpstreamStatus()
|
private val upstreamStatus = GrpcUpstreamStatus(overrideLabels)
|
||||||
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, NoChoiceWithPriorityForkChoice(nodeRating))
|
private val grpcHead = GrpcHead(chain, this, remote, blockConverter, reloadBlock, NoChoiceWithPriorityForkChoice(nodeRating))
|
||||||
private var capabilities: Set<Capability> = emptySet()
|
private var capabilities: Set<Capability> = emptySet()
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,15 @@ import org.slf4j.LoggerFactory
|
|||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
class GrpcUpstreamStatus {
|
class GrpcUpstreamStatus(
|
||||||
|
private val overrideLabels: UpstreamsConfig.Labels?
|
||||||
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val log = LoggerFactory.getLogger(GrpcUpstreamStatus::class.java)
|
private val log = LoggerFactory.getLogger(GrpcUpstreamStatus::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val allLabels: AtomicReference<Collection<UpstreamsConfig.Labels>> = AtomicReference(emptyList())
|
private val allLabels: AtomicReference<Collection<UpstreamsConfig.Labels>> = AtomicReference(emptyList())
|
||||||
private val nodes = AtomicReference<QuorumForLabels>(QuorumForLabels())
|
private val nodes = AtomicReference(QuorumForLabels())
|
||||||
private var targets: CallMethods? = null
|
private var targets: CallMethods? = null
|
||||||
|
|
||||||
fun update(conf: BlockchainOuterClass.DescribeChain) {
|
fun update(conf: BlockchainOuterClass.DescribeChain) {
|
||||||
@@ -39,18 +40,17 @@ class GrpcUpstreamStatus {
|
|||||||
val updateNodes = QuorumForLabels()
|
val updateNodes = QuorumForLabels()
|
||||||
|
|
||||||
conf.nodesList.forEach { remoteNode ->
|
conf.nodesList.forEach { remoteNode ->
|
||||||
|
val labels = UpstreamsConfig.Labels()
|
||||||
|
remoteNode.labelsList.forEach {
|
||||||
|
labels[it.name] = it.value
|
||||||
|
}
|
||||||
|
overrideLabels?.let { labels.putAll(it) }
|
||||||
val node = QuorumForLabels.QuorumItem(
|
val node = QuorumForLabels.QuorumItem(
|
||||||
remoteNode.quorum,
|
remoteNode.quorum,
|
||||||
remoteNode.labelsList.let { provided ->
|
labels
|
||||||
val labels = UpstreamsConfig.Labels()
|
|
||||||
provided.forEach {
|
|
||||||
labels[it.name] = it.value
|
|
||||||
}
|
|
||||||
updateLabels.add(labels)
|
|
||||||
labels
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
updateNodes.add(node)
|
updateNodes.add(node)
|
||||||
|
updateLabels.add(labels)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.nodes.set(updateNodes)
|
this.nodes.set(updateNodes)
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ class GrpcUpstreams(
|
|||||||
private val port: Int,
|
private val port: Int,
|
||||||
private val auth: AuthConfig.ClientTlsAuth? = null,
|
private val auth: AuthConfig.ClientTlsAuth? = null,
|
||||||
private val fileResolver: FileResolver,
|
private val fileResolver: FileResolver,
|
||||||
private val nodeRating: Int
|
private val nodeRating: Int,
|
||||||
|
private val labels: UpstreamsConfig.Labels
|
||||||
) {
|
) {
|
||||||
private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java)
|
private val log = LoggerFactory.getLogger(GrpcUpstreams::class.java)
|
||||||
|
|
||||||
@@ -205,7 +206,7 @@ class GrpcUpstreams(
|
|||||||
val current = known[chain]
|
val current = known[chain]
|
||||||
return if (current == null) {
|
return if (current == null) {
|
||||||
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
||||||
val created = EthereumGrpcUpstream(id, role, chain, client!!, rpcClient)
|
val created = EthereumGrpcUpstream(id, role, chain, client!!, rpcClient, labels)
|
||||||
created.timeout = this.timeout
|
created.timeout = this.timeout
|
||||||
known[chain] = created
|
known[chain] = created
|
||||||
created.start()
|
created.start()
|
||||||
@@ -221,7 +222,7 @@ class GrpcUpstreams(
|
|||||||
val current = known[chain]
|
val current = known[chain]
|
||||||
return if (current == null) {
|
return if (current == null) {
|
||||||
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
||||||
val created = EthereumPosGrpcUpstream(id, role, chain, client!!, rpcClient, nodeRating)
|
val created = EthereumPosGrpcUpstream(id, role, chain, client!!, rpcClient, nodeRating, labels)
|
||||||
created.timeout = this.timeout
|
created.timeout = this.timeout
|
||||||
known[chain] = created
|
known[chain] = created
|
||||||
created.start()
|
created.start()
|
||||||
@@ -237,7 +238,7 @@ class GrpcUpstreams(
|
|||||||
val current = known[chain]
|
val current = known[chain]
|
||||||
return if (current == null) {
|
return if (current == null) {
|
||||||
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
val rpcClient = JsonRpcGrpcClient(client!!, chain, metrics)
|
||||||
val created = BitcoinGrpcUpstream(id, role, chain, client!!, rpcClient)
|
val created = BitcoinGrpcUpstream(id, role, chain, client!!, rpcClient, labels)
|
||||||
created.timeout = this.timeout
|
created.timeout = this.timeout
|
||||||
known[chain] = created
|
known[chain] = created
|
||||||
created.start()
|
created.start()
|
||||||
|
|||||||
@@ -233,7 +233,8 @@ class UpstreamsConfigReaderSpec extends Specification {
|
|||||||
act.upstreams.size() == 2
|
act.upstreams.size() == 2
|
||||||
with(act.upstreams.get(0)) {
|
with(act.upstreams.get(0)) {
|
||||||
connection instanceof UpstreamsConfig.GrpcConnection
|
connection instanceof UpstreamsConfig.GrpcConnection
|
||||||
labels.isEmpty()
|
labels.size() == 1
|
||||||
|
labels["provider"] == "some_service"
|
||||||
}
|
}
|
||||||
with(act.upstreams.get(1)) {
|
with(act.upstreams.get(1)) {
|
||||||
!labels.isEmpty()
|
!labels.isEmpty()
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics))
|
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null)
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
@@ -139,7 +139,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, Chain.ETHEREUM, client, new JsonRpcGrpcClient(client, Chain.ETHEREUM, metrics))
|
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, Chain.ETHEREUM, client, new JsonRpcGrpcClient(client, Chain.ETHEREUM, metrics), null)
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
@@ -201,7 +201,7 @@ class EthereumGrpcUpstreamSpec extends Specification {
|
|||||||
finished.complete(true)
|
finished.complete(true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics))
|
def upstream = new EthereumGrpcUpstream("test", UpstreamsConfig.UpstreamRole.PRIMARY, chain, client, new JsonRpcGrpcClient(client, chain, metrics), null)
|
||||||
upstream.setLag(0)
|
upstream.setLag(0)
|
||||||
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
upstream.update(BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
.setStatus(BlockchainOuterClass.ChainStatus.newBuilder().setQuorum(1).setAvailabilityValue(UpstreamAvailability.OK.grpcId))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class GrpcUpstreamStatusSpec extends Specification {
|
|||||||
|
|
||||||
def "Updates with new labels"() {
|
def "Updates with new labels"() {
|
||||||
setup:
|
setup:
|
||||||
def status = new GrpcUpstreamStatus()
|
def status = new GrpcUpstreamStatus(null)
|
||||||
when:
|
when:
|
||||||
status.update(
|
status.update(
|
||||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
@@ -86,9 +86,74 @@ class GrpcUpstreamStatusSpec extends Specification {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Updates with new labels override"() {
|
||||||
|
setup:
|
||||||
|
def status = new GrpcUpstreamStatus(UpstreamsConfig.Labels.fromMap([fix: "value"]))
|
||||||
|
when:
|
||||||
|
status.update(
|
||||||
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
|
.addNodes(
|
||||||
|
BlockchainOuterClass.NodeDetails.newBuilder()
|
||||||
|
.setQuorum(1)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("test").setValue("foo")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
def act = status.getLabels()
|
||||||
|
then:
|
||||||
|
act.toList() == [
|
||||||
|
UpstreamsConfig.Labels.fromMap([test: "foo", fix: "value"])
|
||||||
|
]
|
||||||
|
|
||||||
|
// replace with new value
|
||||||
|
when:
|
||||||
|
status.update(
|
||||||
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
|
.addNodes(
|
||||||
|
BlockchainOuterClass.NodeDetails.newBuilder()
|
||||||
|
.setQuorum(1)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("test").setValue("bar")
|
||||||
|
).addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("fix").setValue("val")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
act = status.getLabels()
|
||||||
|
then:
|
||||||
|
act.toList() == [
|
||||||
|
UpstreamsConfig.Labels.fromMap([test: "bar", fix: "value"])
|
||||||
|
]
|
||||||
|
|
||||||
|
// more values
|
||||||
|
when:
|
||||||
|
status.update(
|
||||||
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
|
.addNodes(
|
||||||
|
BlockchainOuterClass.NodeDetails.newBuilder()
|
||||||
|
.setQuorum(1)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("test1").setValue("bar")
|
||||||
|
)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("test2").setValue("baz")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
act = status.getLabels()
|
||||||
|
then:
|
||||||
|
act.toList() == [
|
||||||
|
UpstreamsConfig.Labels.fromMap([test1: "bar", test2: "baz", fix: "value"])
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
def "Updates with new nodes"() {
|
def "Updates with new nodes"() {
|
||||||
setup:
|
setup:
|
||||||
def status = new GrpcUpstreamStatus()
|
def status = new GrpcUpstreamStatus(null)
|
||||||
when:
|
when:
|
||||||
status.update(
|
status.update(
|
||||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
@@ -108,9 +173,34 @@ class GrpcUpstreamStatusSpec extends Specification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "Updates with new nodes override labels"() {
|
||||||
|
setup:
|
||||||
|
def status = new GrpcUpstreamStatus(UpstreamsConfig.Labels.fromMap([fix: "value"]))
|
||||||
|
when:
|
||||||
|
status.update(
|
||||||
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
|
.addNodes(
|
||||||
|
BlockchainOuterClass.NodeDetails.newBuilder()
|
||||||
|
.setQuorum(1)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("test").setValue("foo")
|
||||||
|
)
|
||||||
|
.addLabels(
|
||||||
|
BlockchainOuterClass.Label.newBuilder().setName("fix").setValue("val")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
def act = status.getNodes()
|
||||||
|
then:
|
||||||
|
act == new QuorumForLabels().tap {
|
||||||
|
it.add(new QuorumForLabels.QuorumItem(1, UpstreamsConfig.Labels.fromMap([test: "foo", fix: "value"])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def "Updates with methods"() {
|
def "Updates with methods"() {
|
||||||
setup:
|
setup:
|
||||||
def status = new GrpcUpstreamStatus()
|
def status = new GrpcUpstreamStatus(null)
|
||||||
when:
|
when:
|
||||||
status.update(
|
status.update(
|
||||||
BlockchainOuterClass.DescribeChain.newBuilder()
|
BlockchainOuterClass.DescribeChain.newBuilder()
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ defaultOptions:
|
|||||||
|
|
||||||
upstreams:
|
upstreams:
|
||||||
- id: remote
|
- id: remote
|
||||||
|
labels:
|
||||||
|
provider: some_service
|
||||||
connection:
|
connection:
|
||||||
grpc:
|
grpc:
|
||||||
host: "10.2.0.15"
|
host: "10.2.0.15"
|
||||||
|
|||||||
Reference in New Issue
Block a user