mirror of
https://github.com/corda/corda.git
synced 2025-06-15 13:48:14 +00:00
CORDA-892: Make cordform test use new network bootstrapper logic (#2307)
* Make cordform test use new network bootstrapper logic * Fixing review comments * Fix issue with backwards compatibility * Fix issue with setup not being called from CordformDefinitions * Make sure node dir is created (as CordformDefinition uses it directly if setup is overridden Make sure tmp dir is created * Don't crash if node dir is already created * Stop overwriting errors
This commit is contained in:
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=3.0.2
|
gradlePluginsVersion=3.0.3
|
||||||
kotlinVersion=1.1.60
|
kotlinVersion=1.1.60
|
||||||
platformVersion=2
|
platformVersion=2
|
||||||
guavaVersion=21.0
|
guavaVersion=21.0
|
||||||
|
@ -22,6 +22,7 @@ import java.util.jar.JarInputStream
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
open class Cordform : DefaultTask() {
|
open class Cordform : DefaultTask() {
|
||||||
private companion object {
|
private companion object {
|
||||||
|
val nodeJarName = "corda.jar"
|
||||||
private val defaultDirectory: Path = Paths.get("build", "nodes")
|
private val defaultDirectory: Path = Paths.get("build", "nodes")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +133,26 @@ open class Cordform : DefaultTask() {
|
|||||||
fun build() {
|
fun build() {
|
||||||
project.logger.info("Running Cordform task")
|
project.logger.info("Running Cordform task")
|
||||||
initializeConfiguration()
|
initializeConfiguration()
|
||||||
|
nodes.forEach(Node::installConfig)
|
||||||
|
installCordaJar()
|
||||||
installRunScript()
|
installRunScript()
|
||||||
nodes.forEach(Node::build)
|
|
||||||
bootstrapNetwork()
|
bootstrapNetwork()
|
||||||
|
nodes.forEach(Node::build)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the corda fat JAR to the root directory, for the network bootstrapper to use.
|
||||||
|
*/
|
||||||
|
private fun installCordaJar() {
|
||||||
|
val cordaJar = Cordformation.verifyAndGetRuntimeJar(project, "corda")
|
||||||
|
project.copy {
|
||||||
|
it.apply {
|
||||||
|
from(cordaJar)
|
||||||
|
into(directory)
|
||||||
|
rename(cordaJar.name, nodeJarName)
|
||||||
|
fileMode = Cordformation.executableFileMode
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeConfiguration() {
|
private fun initializeConfiguration() {
|
||||||
@ -150,8 +168,8 @@ open class Cordform : DefaultTask() {
|
|||||||
cd.nodeConfigurers.forEach {
|
cd.nodeConfigurers.forEach {
|
||||||
val node = node { }
|
val node = node { }
|
||||||
it.accept(node)
|
it.accept(node)
|
||||||
|
node.additionalCordapps.addAll(cordapps)
|
||||||
node.rootDir(directory)
|
node.rootDir(directory)
|
||||||
node.installCordapps(cordapps)
|
|
||||||
}
|
}
|
||||||
cd.setup { nodeName -> project.projectDir.toPath().resolve(getNodeByName(nodeName)!!.nodeDir.toPath()) }
|
cd.setup { nodeName -> project.projectDir.toPath().resolve(getNodeByName(nodeName)!!.nodeDir.toPath()) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,14 +20,35 @@ class Cordformation : Plugin<Project> {
|
|||||||
* @return A file handle to the file in the JAR.
|
* @return A file handle to the file in the JAR.
|
||||||
*/
|
*/
|
||||||
fun getPluginFile(project: Project, filePathInJar: String): File {
|
fun getPluginFile(project: Project, filePathInJar: String): File {
|
||||||
val archive: File? = project.rootProject.buildscript.configurations
|
val archive = project.rootProject.buildscript.configurations
|
||||||
.single { it.name == "classpath" }
|
.single { it.name == "classpath" }
|
||||||
.find { it.name.contains("cordformation") }
|
.first { it.name.contains("cordformation") }
|
||||||
return project.rootProject.resources.text
|
return project.rootProject.resources.text
|
||||||
.fromArchiveEntry(archive, filePathInJar)
|
.fromArchiveEntry(archive, filePathInJar)
|
||||||
.asFile()
|
.asFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a current built corda jar file
|
||||||
|
*
|
||||||
|
* @param project The project environment this plugin executes in.
|
||||||
|
* @param jarName The name of the JAR you wish to access.
|
||||||
|
* @return A file handle to the file in the JAR.
|
||||||
|
*/
|
||||||
|
fun verifyAndGetRuntimeJar(project: Project, jarName: String): File {
|
||||||
|
val releaseVersion = project.rootProject.ext<String>("corda_release_version")
|
||||||
|
val maybeJar = project.configuration("runtime").filter {
|
||||||
|
"$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString()
|
||||||
|
}
|
||||||
|
if (maybeJar.isEmpty) {
|
||||||
|
throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"")
|
||||||
|
} else {
|
||||||
|
val jar = maybeJar.singleFile
|
||||||
|
require(jar.isFile)
|
||||||
|
return jar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val executableFileMode = "0755".toInt(8)
|
val executableFileMode = "0755".toInt(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ import java.nio.file.Path
|
|||||||
*/
|
*/
|
||||||
class Node(private val project: Project) : CordformNode() {
|
class Node(private val project: Project) : CordformNode() {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
|
||||||
val nodeJarName = "corda.jar"
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val webJarName = "corda-webserver.jar"
|
val webJarName = "corda-webserver.jar"
|
||||||
private val configFileProperty = "configFile"
|
private val configFileProperty = "configFile"
|
||||||
@ -30,10 +28,11 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
* @note Type is any due to gradle's use of "GStrings" - each value will have "toString" called on it
|
* @note Type is any due to gradle's use of "GStrings" - each value will have "toString" called on it
|
||||||
*/
|
*/
|
||||||
var cordapps = mutableListOf<Any>()
|
var cordapps = mutableListOf<Any>()
|
||||||
|
var additionalCordapps = mutableListOf<File>()
|
||||||
private val releaseVersion = project.rootProject.ext<String>("corda_release_version")
|
|
||||||
internal lateinit var nodeDir: File
|
internal lateinit var nodeDir: File
|
||||||
private set
|
private set
|
||||||
|
internal lateinit var rootDir: File
|
||||||
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether this node will use HTTPS communication.
|
* Sets whether this node will use HTTPS communication.
|
||||||
@ -65,16 +64,12 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun build() {
|
internal fun build() {
|
||||||
configureProperties()
|
|
||||||
installCordaJar()
|
|
||||||
if (config.hasPath("webAddress")) {
|
if (config.hasPath("webAddress")) {
|
||||||
installWebserverJar()
|
installWebserverJar()
|
||||||
}
|
}
|
||||||
installAgentJar()
|
installAgentJar()
|
||||||
installBuiltCordapp()
|
installBuiltCordapp()
|
||||||
installCordapps()
|
installCordapps()
|
||||||
installConfig()
|
|
||||||
appendOptionalConfig()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun rootDir(rootDir: Path) {
|
internal fun rootDir(rootDir: Path) {
|
||||||
@ -86,7 +81,9 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
// with loading our custom X509EdDSAEngine.
|
// with loading our custom X509EdDSAEngine.
|
||||||
val organizationName = name.trim().split(",").firstOrNull { it.startsWith("O=") }?.substringAfter("=")
|
val organizationName = name.trim().split(",").firstOrNull { it.startsWith("O=") }?.substringAfter("=")
|
||||||
val dirName = organizationName ?: name
|
val dirName = organizationName ?: name
|
||||||
nodeDir = File(rootDir.toFile(), dirName)
|
this.rootDir = rootDir.toFile()
|
||||||
|
nodeDir = File(this.rootDir, dirName)
|
||||||
|
Files.createDirectories(nodeDir.toPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureProperties() {
|
private fun configureProperties() {
|
||||||
@ -99,26 +96,11 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs the corda fat JAR to the node directory.
|
|
||||||
*/
|
|
||||||
private fun installCordaJar() {
|
|
||||||
val cordaJar = verifyAndGetRuntimeJar("corda")
|
|
||||||
project.copy {
|
|
||||||
it.apply {
|
|
||||||
from(cordaJar)
|
|
||||||
into(nodeDir)
|
|
||||||
rename(cordaJar.name, nodeJarName)
|
|
||||||
fileMode = Cordformation.executableFileMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs the corda webserver JAR to the node directory
|
* Installs the corda webserver JAR to the node directory
|
||||||
*/
|
*/
|
||||||
private fun installWebserverJar() {
|
private fun installWebserverJar() {
|
||||||
val webJar = verifyAndGetRuntimeJar("corda-webserver")
|
val webJar = Cordformation.verifyAndGetRuntimeJar(project, "corda-webserver")
|
||||||
project.copy {
|
project.copy {
|
||||||
it.apply {
|
it.apply {
|
||||||
from(webJar)
|
from(webJar)
|
||||||
@ -141,19 +123,6 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Installs other cordapps to this node's cordapps directory.
|
|
||||||
*/
|
|
||||||
internal fun installCordapps(cordapps: Collection<File> = getCordappList()) {
|
|
||||||
val cordappsDir = File(nodeDir, "cordapps")
|
|
||||||
project.copy {
|
|
||||||
it.apply {
|
|
||||||
from(cordapps)
|
|
||||||
into(cordappsDir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs the jolokia monitoring agent JAR to the node/drivers directory
|
* Installs the jolokia monitoring agent JAR to the node/drivers directory
|
||||||
*/
|
*/
|
||||||
@ -161,8 +130,8 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
val jolokiaVersion = project.rootProject.ext<String>("jolokia_version")
|
val jolokiaVersion = project.rootProject.ext<String>("jolokia_version")
|
||||||
val agentJar = project.configuration("runtime").files {
|
val agentJar = project.configuration("runtime").files {
|
||||||
(it.group == "org.jolokia") &&
|
(it.group == "org.jolokia") &&
|
||||||
(it.name == "jolokia-jvm") &&
|
(it.name == "jolokia-jvm") &&
|
||||||
(it.version == jolokiaVersion)
|
(it.version == jolokiaVersion)
|
||||||
// TODO: revisit when classifier attribute is added. eg && (it.classifier = "agent")
|
// TODO: revisit when classifier attribute is added. eg && (it.classifier = "agent")
|
||||||
}.first() // should always be the jolokia agent fat jar: eg. jolokia-jvm-1.3.7-agent.jar
|
}.first() // should always be the jolokia agent fat jar: eg. jolokia-jvm-1.3.7-agent.jar
|
||||||
project.logger.info("Jolokia agent jar: $agentJar")
|
project.logger.info("Jolokia agent jar: $agentJar")
|
||||||
@ -177,10 +146,7 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun createTempConfigFile(): File {
|
||||||
* Installs the configuration file to this node's directory and detokenises it.
|
|
||||||
*/
|
|
||||||
private fun installConfig() {
|
|
||||||
val options = ConfigRenderOptions
|
val options = ConfigRenderOptions
|
||||||
.defaults()
|
.defaults()
|
||||||
.setOriginComments(false)
|
.setOriginComments(false)
|
||||||
@ -188,16 +154,26 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
.setFormatted(true)
|
.setFormatted(true)
|
||||||
.setJson(false)
|
.setJson(false)
|
||||||
val configFileText = config.root().render(options).split("\n").toList()
|
val configFileText = config.root().render(options).split("\n").toList()
|
||||||
|
|
||||||
// Need to write a temporary file first to use the project.copy, which resolves directories correctly.
|
// Need to write a temporary file first to use the project.copy, which resolves directories correctly.
|
||||||
val tmpDir = File(project.buildDir, "tmp")
|
val tmpDir = File(project.buildDir, "tmp")
|
||||||
val tmpConfFile = File(tmpDir, "node.conf")
|
Files.createDirectories(tmpDir.toPath())
|
||||||
|
var fileName = "${nodeDir.getName()}.conf"
|
||||||
|
val tmpConfFile = File(tmpDir, fileName)
|
||||||
Files.write(tmpConfFile.toPath(), configFileText, StandardCharsets.UTF_8)
|
Files.write(tmpConfFile.toPath(), configFileText, StandardCharsets.UTF_8)
|
||||||
|
return tmpConfFile
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the configuration file to the root directory and detokenises it.
|
||||||
|
*/
|
||||||
|
internal fun installConfig() {
|
||||||
|
configureProperties()
|
||||||
|
val tmpConfFile = createTempConfigFile()
|
||||||
|
appendOptionalConfig(tmpConfFile)
|
||||||
project.copy {
|
project.copy {
|
||||||
it.apply {
|
it.apply {
|
||||||
from(tmpConfFile)
|
from(tmpConfFile)
|
||||||
into(nodeDir)
|
into(rootDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +181,7 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
/**
|
/**
|
||||||
* Appends installed config file with properties from an optional file.
|
* Appends installed config file with properties from an optional file.
|
||||||
*/
|
*/
|
||||||
private fun appendOptionalConfig() {
|
private fun appendOptionalConfig(confFile: File) {
|
||||||
val optionalConfig: File? = when {
|
val optionalConfig: File? = when {
|
||||||
project.findProperty(configFileProperty) != null -> //provided by -PconfigFile command line property when running Gradle task
|
project.findProperty(configFileProperty) != null -> //provided by -PconfigFile command line property when running Gradle task
|
||||||
File(project.findProperty(configFileProperty) as String)
|
File(project.findProperty(configFileProperty) as String)
|
||||||
@ -217,28 +193,22 @@ class Node(private val project: Project) : CordformNode() {
|
|||||||
if (!optionalConfig.exists()) {
|
if (!optionalConfig.exists()) {
|
||||||
project.logger.error("$configFileProperty '$optionalConfig' not found")
|
project.logger.error("$configFileProperty '$optionalConfig' not found")
|
||||||
} else {
|
} else {
|
||||||
val confFile = File(project.buildDir.path + "/../" + nodeDir, "node.conf")
|
|
||||||
confFile.appendBytes(optionalConfig.readBytes())
|
confFile.appendBytes(optionalConfig.readBytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the given JAR amongst the dependencies
|
* Installs other cordapps to this node's cordapps directory.
|
||||||
* @param jarName JAR name without the version part, for example for corda-2.0-SNAPSHOT.jar provide only "corda" as jarName
|
|
||||||
*
|
|
||||||
* @return A file representing found JAR
|
|
||||||
*/
|
*/
|
||||||
private fun verifyAndGetRuntimeJar(jarName: String): File {
|
internal fun installCordapps() {
|
||||||
val maybeJar = project.configuration("runtime").filter {
|
additionalCordapps.addAll(getCordappList())
|
||||||
"$jarName-$releaseVersion.jar" in it.toString() || "$jarName-enterprise-$releaseVersion.jar" in it.toString()
|
val cordappsDir = File(nodeDir, "cordapps")
|
||||||
}
|
project.copy {
|
||||||
if (maybeJar.isEmpty) {
|
it.apply {
|
||||||
throw IllegalStateException("No $jarName JAR found. Have you deployed the Corda project to Maven? Looked for \"$jarName-$releaseVersion.jar\"")
|
from(additionalCordapps)
|
||||||
} else {
|
into(cordappsDir)
|
||||||
val jar = maybeJar.singleFile
|
}
|
||||||
require(jar.isFile)
|
|
||||||
return jar
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,16 +83,20 @@ class NetworkBootstrapper {
|
|||||||
for (confFile in confFiles) {
|
for (confFile in confFiles) {
|
||||||
val nodeName = confFile.fileName.toString().removeSuffix(".conf")
|
val nodeName = confFile.fileName.toString().removeSuffix(".conf")
|
||||||
println("Generating directory for $nodeName")
|
println("Generating directory for $nodeName")
|
||||||
val nodeDir = (directory / nodeName).createDirectory()
|
val nodeDir = (directory / nodeName)
|
||||||
confFile.moveTo(nodeDir / "node.conf")
|
if (!nodeDir.exists()) { nodeDir.createDirectory() }
|
||||||
Files.copy(cordaJar, (nodeDir / "corda.jar"))
|
confFile.moveTo(nodeDir / "node.conf", StandardCopyOption.REPLACE_EXISTING)
|
||||||
|
Files.copy(cordaJar, (nodeDir / "corda.jar"), StandardCopyOption.REPLACE_EXISTING)
|
||||||
}
|
}
|
||||||
Files.delete(cordaJar)
|
Files.delete(cordaJar)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun extractCordaJarTo(directory: Path): Path {
|
private fun extractCordaJarTo(directory: Path): Path {
|
||||||
val cordaJarPath = (directory / "corda.jar")
|
val cordaJarPath = (directory / "corda.jar")
|
||||||
Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath)
|
if (!cordaJarPath.exists()) {
|
||||||
|
println("No corda jar found in root directory. Extracting from jar")
|
||||||
|
Thread.currentThread().contextClassLoader.getResourceAsStream("corda.jar").copyTo(cordaJarPath)
|
||||||
|
}
|
||||||
return cordaJarPath
|
return cordaJarPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user