Netowrk Bootstrapper CLI enhancements (#3634)

This commit is contained in:
Stefano Franz 2018-07-18 15:26:49 +01:00 committed by Katelyn Baker
parent baeb72366c
commit 8585ade599
7 changed files with 26 additions and 25 deletions

View File

@ -1,4 +1,5 @@
@file:JvmName("Main") @file:JvmName("Main")
package net.corda.bootstrapper package net.corda.bootstrapper
import javafx.application.Application import javafx.application.Application
@ -15,7 +16,13 @@ val baseArgs = CliParser()
fun main(args: Array<String>) { fun main(args: Array<String>) {
SerializationEngine.init() SerializationEngine.init()
CommandLine(baseArgs).parse(*args) val commandLine = CommandLine(baseArgs)
commandLine.parse(*args)
if (commandLine.isUsageHelpRequested) {
commandLine.usage(System.out)
return
}
if (baseArgs.gui) { if (baseArgs.gui) {
Application.launch(Gui::class.java) Application.launch(Gui::class.java)

View File

@ -7,7 +7,6 @@ import net.corda.bootstrapper.notaries.NotaryCopier
import net.corda.bootstrapper.notaries.NotaryFinder import net.corda.bootstrapper.notaries.NotaryFinder
import java.io.File import java.io.File
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
interface NetworkBuilder { interface NetworkBuilder {
@ -23,7 +22,6 @@ interface NetworkBuilder {
fun onNodePushed(callback: (PushedNode) -> Unit): NetworkBuilder fun onNodePushed(callback: (PushedNode) -> Unit): NetworkBuilder
fun onNodeInstance(callback: (NodeInstance) -> Unit): NetworkBuilder fun onNodeInstance(callback: (NodeInstance) -> Unit): NetworkBuilder
fun withNodeCounts(map: Map<String, Int>): NetworkBuilder
fun withNetworkName(networtName: String): NetworkBuilder fun withNetworkName(networtName: String): NetworkBuilder
fun withBasedir(baseDir: File): NetworkBuilder fun withBasedir(baseDir: File): NetworkBuilder
fun withBackend(backendType: Backend.BackendType): NetworkBuilder fun withBackend(backendType: Backend.BackendType): NetworkBuilder
@ -104,11 +102,6 @@ private class NetworkBuilderImpl : NetworkBuilder {
return this return this
} }
override fun withNodeCounts(map: Map<String, Int>): NetworkBuilder {
nodeCounts = ConcurrentHashMap(map.entries.map { it.key.toLowerCase() to it.value }.toMap())
return this
}
override fun withNetworkName(networtName: String): NetworkBuilder { override fun withNetworkName(networtName: String): NetworkBuilder {
this.networkName = networtName this.networkName = networtName
return this return this

View File

@ -9,6 +9,7 @@ import net.corda.bootstrapper.nodes.NodeAdder
import net.corda.bootstrapper.nodes.NodeInstantiator import net.corda.bootstrapper.nodes.NodeInstantiator
import net.corda.bootstrapper.toSingleFuture import net.corda.bootstrapper.toSingleFuture
import net.corda.bootstrapper.useAndClose import net.corda.bootstrapper.useAndClose
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import java.io.File import java.io.File
@ -25,7 +26,6 @@ class CommandLineInterface {
val (_, context) = NetworkBuilder.instance() val (_, context) = NetworkBuilder.instance()
.withBasedir(baseDir) .withBasedir(baseDir)
.withNetworkName(networkName) .withNetworkName(networkName)
.withNodeCounts(parsedArgs.nodes)
.onNodeBuild { builtNode -> println("Built node: ${builtNode.name} to image: ${builtNode.localImageId}") } .onNodeBuild { builtNode -> println("Built node: ${builtNode.name} to image: ${builtNode.localImageId}") }
.onNodePushed { pushedNode -> println("Pushed node: ${pushedNode.name} to: ${pushedNode.remoteImageName}") } .onNodePushed { pushedNode -> println("Pushed node: ${pushedNode.name} to: ${pushedNode.remoteImageName}") }
.onNodeInstance { instance -> .onNodeInstance { instance ->
@ -42,7 +42,7 @@ class CommandLineInterface {
val (_, instantiator, _) = Backend.fromContext(context, cacheDir) val (_, instantiator, _) = Backend.fromContext(context, cacheDir)
val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context)) val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context))
parsedArgs.nodesToAdd.map { parsedArgs.nodesToAdd.map {
nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.toLowerCase(), "")) nodeAdder.addNode(context, Constants.ALPHA_NUMERIC_ONLY_REGEX.replace(it.key.toLowerCase(), ""), CordaX500Name.parse(it.value))
}.toSingleFuture().getOrThrow() }.toSingleFuture().getOrThrow()
persistContext(contextFile, objectMapper, context) persistContext(contextFile, objectMapper, context)
} }

View File

@ -8,6 +8,7 @@ import picocli.CommandLine.Option
import java.io.File import java.io.File
open class CliParser { open class CliParser {
@Option(names = arrayOf("-n", "--network-name"), description = arrayOf("The resource grouping to use")) @Option(names = arrayOf("-n", "--network-name"), description = arrayOf("The resource grouping to use"))
var name: String? = null var name: String? = null
@ -20,11 +21,11 @@ open class CliParser {
@Option(names = arrayOf("-b", "--backend"), description = arrayOf("The backend to use when instantiating nodes")) @Option(names = arrayOf("-b", "--backend"), description = arrayOf("The backend to use when instantiating nodes"))
var backendType: Backend.BackendType = Backend.BackendType.LOCAL_DOCKER var backendType: Backend.BackendType = Backend.BackendType.LOCAL_DOCKER
@Option(names = arrayOf("--nodes"), split = ":", description = arrayOf("The number of each node to create. NodeX:2 will create two instances of NodeX")) @Option(names = arrayOf("--add"), split = ":", description = arrayOf("The node to add. Format is <Name>:<X500>. Eg; \"Node1:O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name\""))
var nodes: MutableMap<String, Int> = hashMapOf() var nodesToAdd: MutableMap<String, String> = hashMapOf()
@Option(names = arrayOf("--add", "-a")) @Option(names = arrayOf("-h", "--help"), usageHelp = true, description = arrayOf("display a help message"))
var nodesToAdd: MutableList<String> = arrayListOf() var helpRequested = false
fun isNew(): Boolean { fun isNew(): Boolean {
return nodesToAdd.isEmpty() return nodesToAdd.isEmpty()

View File

@ -20,6 +20,7 @@ import net.corda.bootstrapper.backends.Backend
import net.corda.bootstrapper.context.Context import net.corda.bootstrapper.context.Context
import net.corda.bootstrapper.nodes.* import net.corda.bootstrapper.nodes.*
import net.corda.bootstrapper.notaries.NotaryFinder import net.corda.bootstrapper.notaries.NotaryFinder
import net.corda.core.identity.CordaX500Name
import org.apache.commons.lang3.RandomStringUtils import org.apache.commons.lang3.RandomStringUtils
import org.controlsfx.control.SegmentedButton import org.controlsfx.control.SegmentedButton
import tornadofx.* import tornadofx.*
@ -69,7 +70,6 @@ class BootstrapperView : View("Corda Network Builder") {
} }
} }
val nodeCount = controller.foundNodes.map { it.id to it.count }.toMap()
val result = NetworkBuilder.instance() val result = NetworkBuilder.instance()
.withBasedir(controller.baseDir.get()) .withBasedir(controller.baseDir.get())
.withNetworkName(networkName) .withNetworkName(networkName)
@ -80,7 +80,6 @@ class BootstrapperView : View("Corda Network Builder") {
.onNodeInstancesRequested(controller::addInstanceRequests) .onNodeInstancesRequested(controller::addInstanceRequests)
.onNodeInstance(controller::addInstance) .onNodeInstance(controller::addInstance)
.withBackend(selectedBackEnd) .withBackend(selectedBackEnd)
.withNodeCounts(nodeCount)
.withBackendOptions(backendParams) .withBackendOptions(backendParams)
.build() .build()
@ -117,6 +116,10 @@ class BootstrapperView : View("Corda Network Builder") {
enableWhen { controller.networkContext.isNotNull } enableWhen { controller.networkContext.isNotNull }
action { action {
templateChoiceBox.selectionModel.selectedItem?.let { nodeToAdd -> templateChoiceBox.selectionModel.selectedItem?.let { nodeToAdd ->
val textInputDialog = TextInputDialog("O=Bank A, L=New York, C=US, OU=Org Unit, CN=Service Name")
textInputDialog.title = "X500 of node to add"
val x500ToUse = textInputDialog.showAndWait().orElseGet { null }
val context = controller.networkContext.value val context = controller.networkContext.value
runLater { runLater {
val (_, instantiator, _) = Backend.fromContext( val (_, instantiator, _) = Backend.fromContext(
@ -124,7 +127,7 @@ class BootstrapperView : View("Corda Network Builder") {
File(controller.baseDir.get(), Constants.BOOTSTRAPPER_DIR_NAME)) File(controller.baseDir.get(), Constants.BOOTSTRAPPER_DIR_NAME))
val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context)) val nodeAdder = NodeAdder(context, NodeInstantiator(instantiator, context))
controller.addInstanceRequest(nodeToAdd) controller.addInstanceRequest(nodeToAdd)
nodeAdder.addNode(context, nodeToAdd).handleAsync { instanceInfo, t -> nodeAdder.addNode(context, nodeToAdd, x500ToUse?.let { CordaX500Name.parse(it) }).handleAsync { instanceInfo, t ->
t?.let { t?.let {
GuiUtils.showException("Failed", "Failed to add node", it) GuiUtils.showException("Failed", "Failed to add node", it)
} }
@ -256,10 +259,6 @@ class BootstrapperView : View("Corda Network Builder") {
compareValues(o1.nodeType.toString() + o1.templateId, o2.nodeType.toString() + o2.templateId) * -1 compareValues(o1.nodeType.toString() + o1.templateId, o2.nodeType.toString() + o2.templateId) * -1
}) })
fun clear() {
networkContext.set(null)
}
fun clearAll() { fun clearAll() {
networkContext.set(null) networkContext.set(null)
foundNodes.clear() foundNodes.clear()

View File

@ -2,17 +2,18 @@ package net.corda.bootstrapper.nodes
import net.corda.bootstrapper.containers.instance.InstanceInfo import net.corda.bootstrapper.containers.instance.InstanceInfo
import net.corda.bootstrapper.context.Context import net.corda.bootstrapper.context.Context
import net.corda.core.identity.CordaX500Name
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
class NodeAdder(val context: Context, class NodeAdder(val context: Context,
val nodeInstantiator: NodeInstantiator) { val nodeInstantiator: NodeInstantiator) {
fun addNode(context: Context, nodeGroupName: String): CompletableFuture<InstanceInfo> { fun addNode(context: Context, nodeGroupName: String, x500ToAdd: CordaX500Name?): CompletableFuture<InstanceInfo> {
return synchronized(context) { return synchronized(context) {
val nodeGroup = context.nodes[nodeGroupName]!! val nodeGroup = context.nodes[nodeGroupName]!!
val nodeInfo = nodeGroup.iterator().next() val nodeInfo = nodeGroup.iterator().next()
val currentNodeSize = nodeGroup.size val currentNodeSize = nodeGroup.size
val newInstanceX500 = nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString() val newInstanceX500 = x500ToAdd?.toString() ?: nodeInfo.groupX500!!.copy(commonName = nodeInfo.groupX500.commonName + (currentNodeSize)).toString()
val newInstanceName = nodeGroupName + (currentNodeSize) val newInstanceName = nodeGroupName + (currentNodeSize)
val nextNodeInfo = nodeInfo.copy( val nextNodeInfo = nodeInfo.copy(
instanceX500 = newInstanceX500, instanceX500 = newInstanceX500,

View File

@ -21,10 +21,10 @@ open class NodeBuilder {
val copiedNodeConfig = copiedNode.copiedNodeConfig val copiedNodeConfig = copiedNode.copiedNodeConfig
val nodeDir = copiedNodeConfig.parentFile val nodeDir = copiedNodeConfig.parentFile
if (!copiedNodeConfig.exists()) { if (!copiedNodeConfig.exists()) {
throw IllegalStateException("There is no nodeConfig for dir: " + copiedNodeConfig) throw IllegalStateException("There is no nodeConfig for dir: $copiedNodeConfig")
} }
val nodeConfig = ConfigFactory.parseFile(copiedNodeConfig) val nodeConfig = ConfigFactory.parseFile(copiedNodeConfig)
LOG.info("starting to build docker image for: " + nodeDir) LOG.info("starting to build docker image for: $nodeDir")
val nodeImageId = localDockerClient.buildImageCmd() val nodeImageId = localDockerClient.buildImageCmd()
.withDockerfile(File(nodeDir, "Dockerfile")) .withDockerfile(File(nodeDir, "Dockerfile"))
.withBaseDirectory(nodeDir) .withBaseDirectory(nodeDir)