mirror of
https://github.com/corda/corda.git
synced 2025-06-18 07:08:15 +00:00
Removed basedir from the config file as it's always overwritten by the --base-directory cmd line arg
This commit is contained in:
@ -52,7 +52,7 @@ class P2PSecurityTest : NodeBasedTest() {
|
||||
|
||||
private fun startSimpleNode(legalName: String): SimpleNode {
|
||||
val config = TestNodeConfiguration(
|
||||
basedir = tempFolder.root.toPath() / legalName,
|
||||
baseDirectory = tempFolder.root.toPath() / legalName,
|
||||
myLegalName = legalName,
|
||||
networkMapService = NetworkMapInfo(networkMapNode.configuration.artemisAddress, networkMapNode.info.legalIdentity.name))
|
||||
config.configureWithDevSSLCertificate() // This creates the node's TLS cert with the CN as the legal name
|
||||
|
43
node/src/main/kotlin/net/corda/node/ArgsParser.kt
Normal file
43
node/src/main/kotlin/net/corda/node/ArgsParser.kt
Normal file
@ -0,0 +1,43 @@
|
||||
package net.corda.node
|
||||
|
||||
import com.typesafe.config.Config
|
||||
import joptsimple.OptionParser
|
||||
import net.corda.core.div
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
import java.io.PrintStream
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
class ArgsParser {
|
||||
private val optionParser = OptionParser()
|
||||
// The intent of allowing a command line configurable directory and config path is to allow deployment flexibility.
|
||||
// Other general configuration should live inside the config file unless we regularly need temporary overrides on the command line
|
||||
private val baseDirectoryArg = optionParser
|
||||
.accepts("base-directory", "The node working directory where all the files are kept")
|
||||
.withRequiredArg()
|
||||
.defaultsTo(".")
|
||||
private val configFileArg = optionParser
|
||||
.accepts("config-file", "The path to the config file")
|
||||
.withRequiredArg()
|
||||
.defaultsTo("node.conf")
|
||||
private val logToConsoleArg = optionParser.accepts("log-to-console", "If set, prints logging to the console as well as to a file.")
|
||||
private val helpArg = optionParser.accepts("help").forHelp()
|
||||
|
||||
fun parse(vararg args: String): CmdLineOptions {
|
||||
val optionSet = optionParser.parse(*args)
|
||||
require(!optionSet.has(baseDirectoryArg) || !optionSet.has(configFileArg)) {
|
||||
"${baseDirectoryArg.options()[0]} and ${configFileArg.options()[0]} cannot be specified together"
|
||||
}
|
||||
val baseDirectory = Paths.get(optionSet.valueOf(baseDirectoryArg)).normalize().toAbsolutePath()
|
||||
val configFile = baseDirectory / optionSet.valueOf(configFileArg)
|
||||
return CmdLineOptions(baseDirectory, configFile, optionSet.has(helpArg), optionSet.has(logToConsoleArg))
|
||||
}
|
||||
|
||||
fun printHelp(sink: PrintStream) = optionParser.printHelpOn(sink)
|
||||
}
|
||||
|
||||
data class CmdLineOptions(val baseDirectory: Path, val configFile: Path?, val help: Boolean, val logToConsole: Boolean) {
|
||||
fun loadConfig(allowMissingConfig: Boolean = false, configOverrides: Map<String, Any?> = emptyMap()): Config {
|
||||
return ConfigHelper.loadConfig(baseDirectory, configFile, allowMissingConfig, configOverrides)
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
package net.corda.node
|
||||
|
||||
import com.typesafe.config.ConfigException
|
||||
import joptsimple.OptionParser
|
||||
import net.corda.core.*
|
||||
import net.corda.core.utilities.Emoji
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.utilities.ANSIProgressObserver
|
||||
import org.fusesource.jansi.Ansi
|
||||
@ -14,7 +12,6 @@ import org.slf4j.LoggerFactory
|
||||
import java.lang.management.ManagementFactory
|
||||
import java.net.InetAddress
|
||||
import java.nio.file.Paths
|
||||
import java.time.LocalDate
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
private var renderBasicInfoToConsole = true
|
||||
@ -31,33 +28,26 @@ fun printBasicNodeInfo(description: String, info: String? = null) {
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val startTime = System.currentTimeMillis()
|
||||
checkJavaVersion()
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
|
||||
val parser = OptionParser()
|
||||
// The intent of allowing a command line configurable directory and config path is to allow deployment flexibility.
|
||||
// Other general configuration should live inside the config file unless we regularly need temporary overrides on the command line
|
||||
val baseDirectoryArg = parser.accepts("base-directory", "The directory to put all files under").withOptionalArg()
|
||||
val configFileArg = parser.accepts("config-file", "The path to the config file").withOptionalArg()
|
||||
val logToConsoleArg = parser.accepts("log-to-console", "If set, prints logging to the console as well as to a file.")
|
||||
val helpArg = parser.accepts("help").forHelp()
|
||||
val argsParser = ArgsParser()
|
||||
|
||||
val cmdlineOptions = try {
|
||||
parser.parse(*args)
|
||||
argsParser.parse(*args)
|
||||
} catch (ex: Exception) {
|
||||
println("Unknown command line arguments: ${ex.message}")
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
// Maybe render command line help.
|
||||
if (cmdlineOptions.has(helpArg)) {
|
||||
parser.printHelpOn(System.out)
|
||||
if (cmdlineOptions.help) {
|
||||
argsParser.printHelp(System.out)
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
// Set up logging.
|
||||
if (cmdlineOptions.has(logToConsoleArg)) {
|
||||
if (cmdlineOptions.logToConsole) {
|
||||
// This property is referenced from the XML config file.
|
||||
System.setProperty("consoleLogLevel", "info")
|
||||
renderBasicInfoToConsole = false
|
||||
@ -65,19 +55,17 @@ fun main(args: Array<String>) {
|
||||
|
||||
drawBanner()
|
||||
|
||||
val baseDirectoryPath = if (cmdlineOptions.has(baseDirectoryArg)) Paths.get(cmdlineOptions.valueOf(baseDirectoryArg)) else Paths.get(".").normalize()
|
||||
System.setProperty("log-path", (baseDirectoryPath / "logs").toAbsolutePath().toString())
|
||||
System.setProperty("log-path", (cmdlineOptions.baseDirectory / "logs").toString())
|
||||
|
||||
val log = LoggerFactory.getLogger("Main")
|
||||
printBasicNodeInfo("Logs can be found in", System.getProperty("log-path"))
|
||||
val configFile = if (cmdlineOptions.has(configFileArg)) Paths.get(cmdlineOptions.valueOf(configFileArg)) else null
|
||||
|
||||
val conf = try {
|
||||
FullNodeConfiguration(ConfigHelper.loadConfig(baseDirectoryPath, configFile))
|
||||
FullNodeConfiguration(cmdlineOptions.baseDirectory, cmdlineOptions.loadConfig())
|
||||
} catch (e: ConfigException) {
|
||||
println("Unable to load the configuration file: ${e.rootCause.message}")
|
||||
exitProcess(2)
|
||||
}
|
||||
val dir = conf.basedir.toAbsolutePath().normalize()
|
||||
|
||||
log.info("Main class: ${FullNodeConfiguration::class.java.protectionDomain.codeSource.location.toURI().path}")
|
||||
val info = ManagementFactory.getRuntimeMXBean()
|
||||
@ -87,13 +75,12 @@ fun main(args: Array<String>) {
|
||||
log.info("classpath: ${info.classPath}")
|
||||
log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
|
||||
log.info("Machine: ${InetAddress.getLocalHost().hostName}")
|
||||
log.info("Working Directory: $dir")
|
||||
log.info("Working Directory: ${cmdlineOptions.baseDirectory}")
|
||||
|
||||
try {
|
||||
dir.createDirectories()
|
||||
cmdlineOptions.baseDirectory.createDirectories()
|
||||
|
||||
val node = conf.createNode()
|
||||
|
||||
node.start()
|
||||
printPluginsAndServices(node)
|
||||
|
||||
@ -121,8 +108,8 @@ private fun checkJavaVersion() {
|
||||
Paths.get("").normalize()
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
println("""
|
||||
You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest version.
|
||||
Corda will now exit...""")
|
||||
You are using a version of Java that is not supported (${System.getProperty("java.version")}). Please upgrade to the latest version.
|
||||
Corda will now exit...""")
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
@ -138,13 +125,6 @@ private fun printPluginsAndServices(node: Node) {
|
||||
}
|
||||
|
||||
private fun messageOfTheDay(): Pair<String, String> {
|
||||
// TODO: Remove this next year.
|
||||
val today = LocalDate.now()
|
||||
if (today.isAfter(LocalDate.of(2016, 12, 20)) && today.isBefore(LocalDate.of(2017, 1, 3))) {
|
||||
val claus = if (Emoji.hasEmojiTerminal) Emoji.santaClaus else ""
|
||||
return Pair("The Corda team wishes you a very merry", "christmas and a happy new year! $claus")
|
||||
}
|
||||
|
||||
val messages = arrayListOf(
|
||||
"The only distributed ledger that pays\nhomage to Pac Man in its logo.",
|
||||
"You know, I was a banker once ...\nbut I lost interest. ${Emoji.bagOfCash}",
|
||||
@ -153,7 +133,6 @@ private fun messageOfTheDay(): Pair<String, String> {
|
||||
"\"It's OK computer, I go to sleep after\ntwenty minutes of inactivity too!\"",
|
||||
"It's kind of like a block chain but\ncords sounded healthier than chains.",
|
||||
"Computer science and finance together.\nYou should see our crazy Christmas parties!"
|
||||
|
||||
)
|
||||
if (Emoji.hasEmojiTerminal)
|
||||
messages +=
|
||||
@ -177,5 +156,3 @@ private fun drawBanner() {
|
||||
"""\____/ /_/ \__,_/\__,_/""").reset().newline().newline().fgBrightDefault().bold().
|
||||
a("--- DEVELOPER SNAPSHOT ------------------------------------------------------------").newline().reset())
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,7 +155,7 @@ fun <A> driver(
|
||||
driverDsl = DriverDSL(
|
||||
portAllocation = portAllocation,
|
||||
debugPortAllocation = debugPortAllocation,
|
||||
driverDirectory = driverDirectory,
|
||||
driverDirectory = driverDirectory.toAbsolutePath(),
|
||||
useTestClock = useTestClock,
|
||||
isDebug = isDebug
|
||||
),
|
||||
@ -349,7 +349,6 @@ open class DriverDSL(
|
||||
val baseDirectory = driverDirectory / name
|
||||
val configOverrides = mapOf(
|
||||
"myLegalName" to name,
|
||||
"basedir" to baseDirectory.normalize().toString(),
|
||||
"artemisAddress" to messagingAddress.toString(),
|
||||
"webAddress" to apiAddress.toString(),
|
||||
"extraAdvertisedServiceIds" to advertisedServices.joinToString(","),
|
||||
@ -367,11 +366,14 @@ open class DriverDSL(
|
||||
}
|
||||
) + customOverrides
|
||||
|
||||
val configuration = FullNodeConfiguration(ConfigHelper.loadConfig(
|
||||
baseDirectoryPath = baseDirectory,
|
||||
allowMissingConfig = true,
|
||||
configOverrides = configOverrides
|
||||
))
|
||||
val configuration = FullNodeConfiguration(
|
||||
baseDirectory,
|
||||
ConfigHelper.loadConfig(
|
||||
baseDirectory = baseDirectory,
|
||||
allowMissingConfig = true,
|
||||
configOverrides = configOverrides
|
||||
)
|
||||
)
|
||||
|
||||
val startNode = startNode(executorService, configuration, quasarJarPath, debugPort)
|
||||
registerProcess(startNode)
|
||||
@ -421,11 +423,10 @@ open class DriverDSL(
|
||||
|
||||
val baseDirectory = driverDirectory / networkMapLegalName
|
||||
val config = ConfigHelper.loadConfig(
|
||||
baseDirectoryPath = baseDirectory,
|
||||
baseDirectory = baseDirectory,
|
||||
allowMissingConfig = true,
|
||||
configOverrides = mapOf(
|
||||
"myLegalName" to networkMapLegalName,
|
||||
"basedir" to baseDirectory.normalize().toString(),
|
||||
"artemisAddress" to networkMapAddress.toString(),
|
||||
"webAddress" to apiAddress.toString(),
|
||||
"extraAdvertisedServiceIds" to "",
|
||||
@ -434,7 +435,7 @@ open class DriverDSL(
|
||||
)
|
||||
|
||||
log.info("Starting network-map-service")
|
||||
val startNode = startNode(executorService, FullNodeConfiguration(config), quasarJarPath, debugPort)
|
||||
val startNode = startNode(executorService, FullNodeConfiguration(baseDirectory, config), quasarJarPath, debugPort)
|
||||
registerProcess(startNode)
|
||||
return startNode
|
||||
}
|
||||
@ -456,7 +457,7 @@ open class DriverDSL(
|
||||
debugPort: Int?
|
||||
): ListenableFuture<Process> {
|
||||
// Write node.conf
|
||||
writeConfig(nodeConf.basedir, "node.conf", nodeConf.config)
|
||||
writeConfig(nodeConf.baseDirectory, "node.conf", nodeConf.config)
|
||||
|
||||
val className = "net.corda.node.MainKt" // cannot directly get class for this, so just use string
|
||||
val separator = System.getProperty("file.separator")
|
||||
@ -471,11 +472,11 @@ open class DriverDSL(
|
||||
val javaArgs = listOf(path) +
|
||||
listOf("-Dname=${nodeConf.myLegalName}", "-javaagent:$quasarJarPath") + debugPortArg +
|
||||
listOf("-cp", classpath, className) +
|
||||
"--base-directory=${nodeConf.basedir}"
|
||||
"--base-directory=${nodeConf.baseDirectory}"
|
||||
val builder = ProcessBuilder(javaArgs)
|
||||
builder.redirectError(Paths.get("error.$className.log").toFile())
|
||||
builder.inheritIO()
|
||||
builder.directory(nodeConf.basedir.toFile())
|
||||
builder.directory(nodeConf.baseDirectory.toFile())
|
||||
val process = builder.start()
|
||||
return Futures.allAsList(
|
||||
addressMustBeBound(executorService, nodeConf.artemisAddress),
|
||||
|
@ -203,7 +203,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
|
||||
// Do all of this in a database transaction so anything that might need a connection has one.
|
||||
initialiseDatabasePersistence {
|
||||
val storageServices = initialiseStorageService(configuration.basedir)
|
||||
val storageServices = initialiseStorageService(configuration.baseDirectory)
|
||||
storage = storageServices.first
|
||||
checkpointStorage = storageServices.second
|
||||
netMapCache = InMemoryNetworkMapCache()
|
||||
@ -285,7 +285,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
return advertisedServices.map {
|
||||
val serviceId = it.type.id
|
||||
val serviceName = it.name ?: "$serviceId|${configuration.myLegalName}"
|
||||
val identity = obtainKeyPair(configuration.basedir, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
||||
val identity = obtainKeyPair(configuration.baseDirectory, serviceId + "-private-key", serviceId + "-public", serviceName).first
|
||||
ServiceEntry(it, identity)
|
||||
}
|
||||
}
|
||||
@ -495,8 +495,8 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
stateMachineRecordedTransactionMappingStorage: StateMachineRecordedTransactionMappingStorage) =
|
||||
StorageServiceImpl(attachments, transactionStorage, stateMachineRecordedTransactionMappingStorage)
|
||||
|
||||
protected fun obtainLegalIdentity(): Party = obtainKeyPair(configuration.basedir, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).first
|
||||
protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair(configuration.basedir, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).second
|
||||
protected fun obtainLegalIdentity(): Party = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).first
|
||||
protected fun obtainLegalIdentityKey(): KeyPair = obtainKeyPair(configuration.baseDirectory, PRIVATE_KEY_FILE_NAME, PUBLIC_IDENTITY_FILE_NAME).second
|
||||
|
||||
private fun obtainKeyPair(dir: Path, privateKeyFileName: String, publicKeyFileName: String, serviceName: String? = null): Pair<Party, KeyPair> {
|
||||
// Load the private identity key, creating it if necessary. The identity key is a long term well known key that
|
||||
@ -545,6 +545,6 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
||||
}
|
||||
|
||||
protected fun createNodeDir() {
|
||||
configuration.basedir.createDirectories()
|
||||
configuration.baseDirectory.createDirectories()
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ class Node(override val configuration: FullNodeConfiguration,
|
||||
override fun makeUniquenessProvider(type: ServiceType): UniquenessProvider {
|
||||
return when (type) {
|
||||
RaftValidatingNotaryService.type -> with(configuration) {
|
||||
RaftUniquenessProvider(basedir, notaryNodeAddress!!, notaryClusterAddresses, database, configuration)
|
||||
RaftUniquenessProvider(baseDirectory, notaryNodeAddress!!, notaryClusterAddresses, database, configuration)
|
||||
}
|
||||
else -> PersistentUniquenessProvider()
|
||||
}
|
||||
@ -393,7 +393,7 @@ class Node(override val configuration: FullNodeConfiguration,
|
||||
// file that we'll do our best to delete on exit. But if we don't, it'll be overwritten next time. If it already
|
||||
// exists, we try to take the file lock first before replacing it and if that fails it means we're being started
|
||||
// twice with the same directory: that's a user error and we should bail out.
|
||||
val pidPath = configuration.basedir / "process-id"
|
||||
val pidPath = configuration.baseDirectory / "process-id"
|
||||
val file = pidPath.toFile()
|
||||
if (!file.exists()) {
|
||||
file.createNewFile()
|
||||
@ -402,7 +402,7 @@ class Node(override val configuration: FullNodeConfiguration,
|
||||
val f = RandomAccessFile(file, "rw")
|
||||
val l = f.channel.tryLock()
|
||||
if (l == null) {
|
||||
log.error("It appears there is already a node running with the specified data directory ${configuration.basedir}")
|
||||
log.error("It appears there is already a node running with the specified data directory ${configuration.baseDirectory}")
|
||||
log.error("Shut that other node down and try again. It may have process ID ${file.readText()}")
|
||||
System.exit(1)
|
||||
}
|
||||
|
@ -25,27 +25,28 @@ import kotlin.reflect.KProperty
|
||||
import kotlin.reflect.jvm.javaType
|
||||
|
||||
object ConfigHelper {
|
||||
val log = loggerFor<ConfigHelper>()
|
||||
private val log = loggerFor<ConfigHelper>()
|
||||
|
||||
fun loadConfig(baseDirectoryPath: Path,
|
||||
fun loadConfig(baseDirectory: Path,
|
||||
configFileOverride: Path? = null,
|
||||
allowMissingConfig: Boolean = false,
|
||||
configOverrides: Map<String, Any?> = emptyMap()): Config {
|
||||
|
||||
val defaultConfig = ConfigFactory.parseResources("reference.conf", ConfigParseOptions.defaults().setAllowMissing(false))
|
||||
|
||||
val normalisedBaseDir = baseDirectoryPath.normalize()
|
||||
val configFile = (configFileOverride?.normalize() ?: normalisedBaseDir / "node.conf").toFile()
|
||||
val appConfig = ConfigFactory.parseFile(configFile, ConfigParseOptions.defaults().setAllowMissing(allowMissingConfig))
|
||||
val configFile = configFileOverride ?: baseDirectory / "node.conf"
|
||||
val appConfig = ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(allowMissingConfig))
|
||||
|
||||
val overridesMap = HashMap<String, Any?>() // If we do require a few other command line overrides eg for a nicer development experience they would go inside this map.
|
||||
overridesMap.putAll(configOverrides)
|
||||
overridesMap["basedir"] = normalisedBaseDir.toAbsolutePath().toString()
|
||||
val overrideConfig = ConfigFactory.parseMap(overridesMap)
|
||||
val overrideConfig = ConfigFactory.parseMap(configOverrides + mapOf(
|
||||
// Add substitution values here
|
||||
"basedir" to baseDirectory.toString())
|
||||
)
|
||||
|
||||
val mergedAndResolvedConfig = overrideConfig.withFallback(appConfig).withFallback(defaultConfig).resolve()
|
||||
log.info("Config:\n ${mergedAndResolvedConfig.root().render(ConfigRenderOptions.defaults())}")
|
||||
return mergedAndResolvedConfig
|
||||
val finalConfig = overrideConfig
|
||||
.withFallback(appConfig)
|
||||
.withFallback(defaultConfig)
|
||||
.resolve()
|
||||
log.info("Config:\n${finalConfig.root().render(ConfigRenderOptions.defaults())}")
|
||||
return finalConfig
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,12 +75,9 @@ class OptionalConfig<out T>(val conf: Config, val lambda: () -> T) {
|
||||
operator fun getValue(receiver: Any, metadata: KProperty<*>): T {
|
||||
return if (conf.hasPath(metadata.name)) conf.getValue(receiver, metadata) else lambda()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun <T> Config.getOrElse(lambda: () -> T): OptionalConfig<T> {
|
||||
return OptionalConfig(this, lambda)
|
||||
}
|
||||
fun <T> Config.getOrElse(lambda: () -> T): OptionalConfig<T> = OptionalConfig(this, lambda)
|
||||
|
||||
fun Config.getProperties(path: String): Properties {
|
||||
val obj = this.getObject(path)
|
||||
@ -106,7 +104,7 @@ inline fun <reified T : Any> Config.getListOrElse(path: String, default: Config.
|
||||
fun NodeConfiguration.configureWithDevSSLCertificate() = configureDevKeyAndTrustStores(myLegalName)
|
||||
|
||||
private fun NodeSSLConfiguration.configureDevKeyAndTrustStores(myLegalName: String) {
|
||||
certificatesPath.createDirectories()
|
||||
certificatesDirectory.createDirectories()
|
||||
if (!trustStorePath.exists()) {
|
||||
javaClass.classLoader.getResourceAsStream("net/corda/node/internal/certificates/cordatruststore.jks").copyTo(trustStorePath)
|
||||
}
|
||||
@ -121,7 +119,7 @@ private fun NodeSSLConfiguration.configureDevKeyAndTrustStores(myLegalName: Stri
|
||||
// TODO Move this to CoreTestUtils.kt once we can pry this from the explorer
|
||||
@JvmOverloads
|
||||
fun configureTestSSL(legalName: String = "Mega Corp."): NodeSSLConfiguration = object : NodeSSLConfiguration {
|
||||
override val certificatesPath = Files.createTempDirectory("certs")
|
||||
override val certificatesDirectory = Files.createTempDirectory("certs")
|
||||
override val keyStorePassword: String get() = "cordacadevpass"
|
||||
override val trustStorePassword: String get() = "trustpass"
|
||||
|
||||
|
@ -13,17 +13,20 @@ import net.corda.node.utilities.TestClock
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
|
||||
// TODO Rename this to SSLConfiguration as it's also used by non-node components
|
||||
interface NodeSSLConfiguration {
|
||||
val keyStorePassword: String
|
||||
val trustStorePassword: String
|
||||
val certificatesPath: Path
|
||||
val keyStorePath: Path get() = certificatesPath / "sslkeystore.jks"
|
||||
val trustStorePath: Path get() = certificatesPath / "truststore.jks"
|
||||
val certificatesDirectory: Path
|
||||
// TODO Rename to keyStoreFile
|
||||
val keyStorePath: Path get() = certificatesDirectory / "sslkeystore.jks"
|
||||
// TODO Rename to trustStoreFile
|
||||
val trustStorePath: Path get() = certificatesDirectory / "truststore.jks"
|
||||
}
|
||||
|
||||
interface NodeConfiguration : NodeSSLConfiguration {
|
||||
val basedir: Path
|
||||
override val certificatesPath: Path get() = basedir / "certificates"
|
||||
val baseDirectory: Path
|
||||
override val certificatesDirectory: Path get() = baseDirectory / "certificates"
|
||||
val myLegalName: String
|
||||
val networkMapService: NetworkMapInfo?
|
||||
val nearestCity: String
|
||||
@ -34,8 +37,10 @@ interface NodeConfiguration : NodeSSLConfiguration {
|
||||
val devMode: Boolean
|
||||
}
|
||||
|
||||
class FullNodeConfiguration(val config: Config) : NodeConfiguration {
|
||||
override val basedir: Path by config
|
||||
/**
|
||||
* [baseDirectory] is not retrieved from the config file but rather from a command line argument.
|
||||
*/
|
||||
class FullNodeConfiguration(override val baseDirectory: Path, val config: Config) : NodeConfiguration {
|
||||
override val myLegalName: String by config
|
||||
override val nearestCity: String by config
|
||||
override val emailAddress: String by config
|
||||
|
@ -103,7 +103,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
private var networkChangeHandle: Subscription? = null
|
||||
|
||||
init {
|
||||
config.basedir.expectedOnDefaultFileSystem()
|
||||
config.baseDirectory.expectedOnDefaultFileSystem()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,7 +143,7 @@ class ArtemisMessagingServer(override val config: NodeConfiguration,
|
||||
}
|
||||
|
||||
private fun createArtemisConfig(): Configuration = ConfigurationImpl().apply {
|
||||
val artemisDir = config.basedir / "artemis"
|
||||
val artemisDir = config.baseDirectory / "artemis"
|
||||
bindingsDirectory = (artemisDir / "bindings").toString()
|
||||
journalDirectory = (artemisDir / "journal").toString()
|
||||
largeMessagesDirectory = (artemisDir / "large-messages").toString()
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.corda.node.utilities.certsigning
|
||||
|
||||
import joptsimple.OptionParser
|
||||
import net.corda.core.*
|
||||
import net.corda.core.crypto.X509Utilities
|
||||
import net.corda.core.crypto.X509Utilities.CORDA_CLIENT_CA
|
||||
@ -9,12 +8,12 @@ import net.corda.core.crypto.X509Utilities.CORDA_ROOT_CA
|
||||
import net.corda.core.crypto.X509Utilities.addOrReplaceCertificate
|
||||
import net.corda.core.crypto.X509Utilities.addOrReplaceKey
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.node.services.config.ConfigHelper
|
||||
import net.corda.node.ArgsParser
|
||||
import net.corda.node.services.config.FullNodeConfiguration
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.config.getValue
|
||||
import net.corda.node.utilities.certsigning.CertificateSigner.Companion.log
|
||||
import java.net.URL
|
||||
import java.nio.file.Paths
|
||||
import java.security.KeyPair
|
||||
import java.security.cert.Certificate
|
||||
import kotlin.system.exitProcess
|
||||
@ -32,7 +31,7 @@ class CertificateSigner(val config: NodeConfiguration, val certService: Certific
|
||||
}
|
||||
|
||||
fun buildKeyStore() {
|
||||
config.certificatesPath.createDirectories()
|
||||
config.certificatesDirectory.createDirectories()
|
||||
|
||||
val caKeyStore = X509Utilities.loadOrCreateKeyStore(config.keyStorePath, config.keyStorePassword)
|
||||
|
||||
@ -97,7 +96,7 @@ class CertificateSigner(val config: NodeConfiguration, val certService: Certific
|
||||
* @return Request ID return from the server.
|
||||
*/
|
||||
private fun submitCertificateSigningRequest(keyPair: KeyPair): String {
|
||||
val requestIdStore = config.certificatesPath / "certificate-request-id.txt"
|
||||
val requestIdStore = config.certificatesDirectory / "certificate-request-id.txt"
|
||||
// Retrieve request id from file if exists, else post a request to server.
|
||||
return if (!requestIdStore.exists()) {
|
||||
val request = X509Utilities.createCertificateSigningRequest(config.myLegalName, config.nearestCity, config.emailAddress, keyPair)
|
||||
@ -112,30 +111,21 @@ class CertificateSigner(val config: NodeConfiguration, val certService: Certific
|
||||
}
|
||||
}
|
||||
|
||||
object ParamsSpec {
|
||||
val parser = OptionParser()
|
||||
val baseDirectoryArg = parser.accepts("base-dir", "Working directory of Corda Node.").withRequiredArg().defaultsTo(".")
|
||||
val configFileArg = parser.accepts("config-file", "The path to the config file.").withRequiredArg()
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val argsParser = ArgsParser()
|
||||
val cmdlineOptions = try {
|
||||
ParamsSpec.parser.parse(*args)
|
||||
argsParser.parse(*args)
|
||||
} catch (ex: Exception) {
|
||||
CertificateSigner.log.error("Unable to parse args", ex)
|
||||
ParamsSpec.parser.printHelpOn(System.out)
|
||||
log.error("Unable to parse args", ex)
|
||||
argsParser.printHelp(System.out)
|
||||
exitProcess(1)
|
||||
}
|
||||
val baseDirectoryPath = Paths.get(cmdlineOptions.valueOf(ParamsSpec.baseDirectoryArg))
|
||||
val configFile = if (cmdlineOptions.has(ParamsSpec.configFileArg)) Paths.get(cmdlineOptions.valueOf(ParamsSpec.configFileArg)) else null
|
||||
|
||||
val config = ConfigHelper.loadConfig(baseDirectoryPath, configFile, allowMissingConfig = true).let { config ->
|
||||
object : NodeConfiguration by FullNodeConfiguration(config) {
|
||||
val certificateSigningService: URL by config
|
||||
}
|
||||
val config = cmdlineOptions.loadConfig(allowMissingConfig = true)
|
||||
val configuration = object : NodeConfiguration by FullNodeConfiguration(cmdlineOptions.baseDirectory, config) {
|
||||
val certificateSigningService: URL by config
|
||||
}
|
||||
|
||||
// TODO: Use HTTPS instead
|
||||
CertificateSigner(config, HTTPCertificateSigningService(config.certificateSigningService)).buildKeyStore()
|
||||
CertificateSigner(configuration, HTTPCertificateSigningService(configuration.certificateSigningService)).buildKeyStore()
|
||||
}
|
||||
|
||||
|
86
node/src/test/kotlin/net/corda/node/ArgsParserTest.kt
Normal file
86
node/src/test/kotlin/net/corda/node/ArgsParserTest.kt
Normal file
@ -0,0 +1,86 @@
|
||||
package net.corda.node
|
||||
|
||||
import joptsimple.OptionException
|
||||
import net.corda.core.div
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
|
||||
class ArgsParserTest {
|
||||
private val parser = ArgsParser()
|
||||
private val workingDirectory = Paths.get(".").normalize().toAbsolutePath()
|
||||
|
||||
@Test
|
||||
fun `no command line arguments`() {
|
||||
assertThat(parser.parse()).isEqualTo(CmdLineOptions(
|
||||
baseDirectory = workingDirectory,
|
||||
configFile = workingDirectory / "node.conf",
|
||||
help = false,
|
||||
logToConsole = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `just base-directory with relative path`() {
|
||||
val expectedBaseDir = Paths.get("tmp").normalize().toAbsolutePath()
|
||||
val cmdLineOptions = parser.parse("--base-directory", "tmp")
|
||||
assertThat(cmdLineOptions).isEqualTo(CmdLineOptions(
|
||||
baseDirectory = expectedBaseDir,
|
||||
configFile = expectedBaseDir / "node.conf",
|
||||
help = false,
|
||||
logToConsole = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `just base-directory with absolute path`() {
|
||||
val baseDirectory = Paths.get("tmp").normalize().toAbsolutePath()
|
||||
val cmdLineOptions = parser.parse("--base-directory", baseDirectory.toString())
|
||||
assertThat(cmdLineOptions).isEqualTo(CmdLineOptions(
|
||||
baseDirectory = baseDirectory,
|
||||
configFile = baseDirectory / "node.conf",
|
||||
help = false,
|
||||
logToConsole = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `just config-file with relative path`() {
|
||||
val cmdLineOptions = parser.parse("--config-file", "different.conf")
|
||||
assertThat(cmdLineOptions).isEqualTo(CmdLineOptions(
|
||||
baseDirectory = workingDirectory,
|
||||
configFile = workingDirectory / "different.conf",
|
||||
help = false,
|
||||
logToConsole = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `just config-file with absolute path`() {
|
||||
val configFile = Paths.get("tmp", "a.conf").normalize().toAbsolutePath()
|
||||
val cmdLineOptions = parser.parse("--config-file", configFile.toString())
|
||||
assertThat(cmdLineOptions).isEqualTo(CmdLineOptions(
|
||||
baseDirectory = workingDirectory,
|
||||
configFile = configFile,
|
||||
help = false,
|
||||
logToConsole = false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `both base-directory and config-file`() {
|
||||
assertThatExceptionOfType(IllegalArgumentException::class.java).isThrownBy {
|
||||
parser.parse("--base-directory", "base", "--config-file", "conf")
|
||||
}.withMessageContaining("base-directory").withMessageContaining("config-file")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `base-directory without argument`() {
|
||||
assertThatExceptionOfType(OptionException::class.java).isThrownBy {
|
||||
parser.parse("--base-directory")
|
||||
}.withMessageContaining("base-directory")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `config-file without argument`() {
|
||||
assertThatExceptionOfType(OptionException::class.java).isThrownBy {
|
||||
parser.parse("--config-file")
|
||||
}.withMessageContaining("config-file")
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import net.corda.node.services.config.FullNodeConfiguration
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
|
||||
class RPCUserServiceImplTest {
|
||||
|
||||
@ -69,6 +70,6 @@ class RPCUserServiceImplTest {
|
||||
}
|
||||
|
||||
private fun loadWithContents(configString: String): RPCUserServiceImpl {
|
||||
return RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.parseString(configString)))
|
||||
return RPCUserServiceImpl(FullNodeConfiguration(Paths.get("."), ConfigFactory.parseString(configString)))
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ import com.google.common.net.HostAndPort
|
||||
import com.google.common.util.concurrent.Futures
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.google.common.util.concurrent.SettableFuture
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import com.typesafe.config.ConfigFactory.empty
|
||||
import net.corda.core.crypto.composite
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import net.corda.core.messaging.Message
|
||||
@ -67,9 +67,10 @@ class ArtemisMessagingTests {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
userService = RPCUserServiceImpl(FullNodeConfiguration(ConfigFactory.empty()))
|
||||
val baseDirectory = temporaryFolder.root.toPath()
|
||||
userService = RPCUserServiceImpl(FullNodeConfiguration(baseDirectory, empty()))
|
||||
config = TestNodeConfiguration(
|
||||
basedir = temporaryFolder.newFolder().toPath(),
|
||||
baseDirectory = baseDirectory,
|
||||
myLegalName = "me",
|
||||
networkMapService = null)
|
||||
LogHelper.setLevel(PersistentUniquenessProvider::class)
|
||||
|
@ -35,7 +35,7 @@ class CertificateSignerTest {
|
||||
}
|
||||
|
||||
val config = TestNodeConfiguration(
|
||||
basedir = tempFolder.root.toPath(),
|
||||
baseDirectory = tempFolder.root.toPath(),
|
||||
myLegalName = "me",
|
||||
networkMapService = null)
|
||||
|
||||
@ -65,6 +65,6 @@ class CertificateSignerTest {
|
||||
assertFalse(containsAlias(X509Utilities.CORDA_ROOT_CA_PRIVATE_KEY))
|
||||
}
|
||||
|
||||
assertEquals(id, (config.certificatesPath / "certificate-request-id.txt").readLines { it.findFirst().get() })
|
||||
assertEquals(id, (config.certificatesDirectory / "certificate-request-id.txt").readLines { it.findFirst().get() })
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user