mirror of
https://github.com/corda/corda.git
synced 2025-02-04 02:01:13 +00:00
Move all the configuration for running doorman in its configuration f… (#104)
* Move all the configuration for running doorman in its configuration files
This commit is contained in:
parent
fffcdb47da
commit
233f1fb8e2
6
.idea/compiler.xml
generated
6
.idea/compiler.xml
generated
@ -46,6 +46,8 @@
|
|||||||
<module name="finance_integrationTest" target="1.8" />
|
<module name="finance_integrationTest" target="1.8" />
|
||||||
<module name="finance_main" target="1.8" />
|
<module name="finance_main" target="1.8" />
|
||||||
<module name="finance_test" target="1.8" />
|
<module name="finance_test" target="1.8" />
|
||||||
|
<module name="gradle-plugins-cordform-common_main" target="1.8" />
|
||||||
|
<module name="gradle-plugins-cordform-common_test" target="1.8" />
|
||||||
<module name="graphs_main" target="1.8" />
|
<module name="graphs_main" target="1.8" />
|
||||||
<module name="graphs_test" target="1.8" />
|
<module name="graphs_test" target="1.8" />
|
||||||
<module name="intellij-plugin_main" target="1.8" />
|
<module name="intellij-plugin_main" target="1.8" />
|
||||||
@ -88,8 +90,12 @@
|
|||||||
<module name="notary-demo_test" target="1.8" />
|
<module name="notary-demo_test" target="1.8" />
|
||||||
<module name="perftestcordapp_main" target="1.8" />
|
<module name="perftestcordapp_main" target="1.8" />
|
||||||
<module name="perftestcordapp_test" target="1.8" />
|
<module name="perftestcordapp_test" target="1.8" />
|
||||||
|
<module name="publish-utils_main" target="1.8" />
|
||||||
|
<module name="publish-utils_test" target="1.8" />
|
||||||
<module name="quasar-hook_main" target="1.8" />
|
<module name="quasar-hook_main" target="1.8" />
|
||||||
<module name="quasar-hook_test" target="1.8" />
|
<module name="quasar-hook_test" target="1.8" />
|
||||||
|
<module name="quasar-utils_main" target="1.8" />
|
||||||
|
<module name="quasar-utils_test" target="1.8" />
|
||||||
<module name="rpc_integrationTest" target="1.8" />
|
<module name="rpc_integrationTest" target="1.8" />
|
||||||
<module name="rpc_main" target="1.8" />
|
<module name="rpc_main" target="1.8" />
|
||||||
<module name="rpc_smokeTest" target="1.8" />
|
<module name="rpc_smokeTest" target="1.8" />
|
||||||
|
@ -15,6 +15,50 @@ This is an example of what a Doorman configuration file might look like:
|
|||||||
Invoke Doorman with ``-?`` for a full list of supported command-line arguments.
|
Invoke Doorman with ``-?`` for a full list of supported command-line arguments.
|
||||||
|
|
||||||
|
|
||||||
|
Configuration parameters
|
||||||
|
------------------------
|
||||||
|
Allowed parameters are:
|
||||||
|
|
||||||
|
:keystorePassword: the keystore password
|
||||||
|
|
||||||
|
:caPrivateKeyPassword: the ca private key password
|
||||||
|
|
||||||
|
:rootKeystorePassword: Password for the root store
|
||||||
|
|
||||||
|
:rootPrivateKeyPassword: Password for the root private key
|
||||||
|
|
||||||
|
:host: host on which doorman runs
|
||||||
|
|
||||||
|
:port: port on which doorman runs
|
||||||
|
|
||||||
|
:mode: must be one of: DOORMAN (default), CA_KEYGEN, ROOT_KEYGEN.
|
||||||
|
|
||||||
|
:approveAll: Whether to approve all request (defaults to false), this is for debug only.
|
||||||
|
|
||||||
|
:databaseProperties: database properties
|
||||||
|
|
||||||
|
:dataSourceProperties: datasoruce properties
|
||||||
|
|
||||||
|
:jiraConfig: The Jira configuration
|
||||||
|
|
||||||
|
:address: The URL to use to connect to Jira
|
||||||
|
|
||||||
|
:projectCode: The project code on Jira
|
||||||
|
|
||||||
|
:username: Username for Jira
|
||||||
|
|
||||||
|
:password: Password for Jira
|
||||||
|
|
||||||
|
:doneTransitionCode: Jira status to put approved tickets in
|
||||||
|
|
||||||
|
:keystorePath: Path for the keystore
|
||||||
|
|
||||||
|
:rootStorePath: Path for the root keystore
|
||||||
|
|
||||||
|
:approveInterval: How often to process Jira approved requests in seconds
|
||||||
|
|
||||||
|
:signInterval: How often to sign the network map in seconds
|
||||||
|
|
||||||
Bootstrapping the network parameters
|
Bootstrapping the network parameters
|
||||||
------------------------------------
|
------------------------------------
|
||||||
When Doorman is running it will serve the current network parameters. The first time Doorman is
|
When Doorman is running it will serve the current network parameters. The first time Doorman is
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
basedir = "."
|
||||||
host = localhost
|
host = localhost
|
||||||
port = 0
|
port = 0
|
||||||
keystorePath = ${basedir}"/certificates/caKeystore.jks"
|
keystorePath = ${basedir}"/certificates/caKeystore.jks"
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
|
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
||||||
import com.r3.corda.networkmanage.common.utils.toConfigWithOptions
|
import com.r3.corda.networkmanage.common.utils.toConfigWithOptions
|
||||||
import com.r3.corda.networkmanage.doorman.DoormanParameters.Companion.DEFAULT_APPROVE_INTERVAL
|
import com.r3.corda.networkmanage.doorman.DoormanParameters.Companion.DEFAULT_APPROVE_INTERVAL
|
||||||
import com.r3.corda.networkmanage.doorman.DoormanParameters.Companion.DEFAULT_SIGN_INTERVAL
|
import com.r3.corda.networkmanage.doorman.DoormanParameters.Companion.DEFAULT_SIGN_INTERVAL
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigParseOptions
|
import com.typesafe.config.ConfigParseOptions
|
||||||
|
import joptsimple.OptionParser
|
||||||
|
import net.corda.core.internal.isRegularFile
|
||||||
|
import net.corda.core.internal.exists
|
||||||
import net.corda.core.internal.div
|
import net.corda.core.internal.div
|
||||||
import net.corda.core.utilities.seconds
|
import net.corda.core.utilities.seconds
|
||||||
import net.corda.nodeapi.config.parseAs
|
import net.corda.nodeapi.config.parseAs
|
||||||
@ -13,24 +17,22 @@ import java.nio.file.Paths
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class DoormanParameters(val basedir: Path,
|
data class DoormanParameters(val keystorePassword: String?,
|
||||||
val keystorePassword: String?,
|
|
||||||
val caPrivateKeyPassword: String?,
|
val caPrivateKeyPassword: String?,
|
||||||
val rootKeystorePassword: String?,
|
val rootKeystorePassword: String?,
|
||||||
val rootPrivateKeyPassword: String?,
|
val rootPrivateKeyPassword: String?,
|
||||||
val host: String,
|
val host: String,
|
||||||
val port: Int,
|
val port: Int,
|
||||||
val dataSourceProperties: Properties,
|
val dataSourceProperties: Properties,
|
||||||
val mode: Mode,
|
val mode: Mode = Mode.DOORMAN,
|
||||||
val approveAll: Boolean = false,
|
val approveAll: Boolean = false,
|
||||||
val databaseProperties: Properties? = null,
|
val databaseProperties: Properties? = null,
|
||||||
val jiraConfig: JiraConfig? = null,
|
val jiraConfig: JiraConfig? = null,
|
||||||
val keystorePath: Path? = null, // basedir / "certificates" / "caKeystore.jks",
|
val keystorePath: Path? = null,
|
||||||
val rootStorePath: Path? = null, // basedir / "certificates" / "rootCAKeystore.jks"
|
val rootStorePath: Path? = null,
|
||||||
// TODO Change these to Duration in the future
|
// TODO Change these to Duration in the future
|
||||||
val approveInterval: Long = DEFAULT_APPROVE_INTERVAL,
|
val approveInterval: Long = DEFAULT_APPROVE_INTERVAL,
|
||||||
val signInterval: Long = DEFAULT_SIGN_INTERVAL,
|
val signInterval: Long = DEFAULT_SIGN_INTERVAL
|
||||||
val initialNetworkParameters: Path
|
|
||||||
) {
|
) {
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
DOORMAN, CA_KEYGEN, ROOT_KEYGEN
|
DOORMAN, CA_KEYGEN, ROOT_KEYGEN
|
||||||
@ -50,30 +52,48 @@ data class DoormanParameters(val basedir: Path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseParameters(vararg args: String): DoormanParameters {
|
data class CommandLineOptions(val configFile: Path,
|
||||||
val argConfig = args.toConfigWithOptions {
|
val initialNetworkParameters: Path) {
|
||||||
accepts("basedir", "Overriding configuration filepath, default to current directory.").withRequiredArg().defaultsTo(".").describedAs("filepath")
|
init {
|
||||||
accepts("configFile", "Overriding configuration file, default to <<current directory>>/node.conf.").withRequiredArg().describedAs("filepath")
|
check(configFile.isRegularFile()) { "Config file $configFile does not exist" }
|
||||||
accepts("mode", "Execution mode. Allowed values: ${DoormanParameters.Mode.values().toList()}").withRequiredArg().defaultsTo(DoormanParameters.Mode.DOORMAN.name)
|
check(initialNetworkParameters.isRegularFile()) { "Initial network parameters file $initialNetworkParameters does not exist" }
|
||||||
accepts("keystorePath", "CA keystore filepath").withRequiredArg().describedAs("filepath")
|
|
||||||
accepts("rootStorePath", "Root CA keystore filepath").withRequiredArg().describedAs("filepath")
|
|
||||||
accepts("keystorePassword", "CA keystore password.").withRequiredArg().describedAs("password")
|
|
||||||
accepts("caPrivateKeyPassword", "CA private key password.").withRequiredArg().describedAs("password")
|
|
||||||
accepts("rootKeystorePassword", "Root CA keystore password.").withRequiredArg().describedAs("password")
|
|
||||||
accepts("rootPrivateKeyPassword", "Root private key password.").withRequiredArg().describedAs("password")
|
|
||||||
accepts("host", "Doorman web service host override").withRequiredArg().describedAs("hostname")
|
|
||||||
accepts("port", "Doorman web service port override").withRequiredArg().ofType(Int::class.java).describedAs("port number")
|
|
||||||
accepts("approveInterval", "Time interval (in seconds) in which CSRs are approved (default: ${DEFAULT_APPROVE_INTERVAL})").withRequiredArg().ofType(Long::class.java).defaultsTo(DEFAULT_APPROVE_INTERVAL)
|
|
||||||
accepts("signInterval", "Time interval (in seconds) in which network map is signed (default: ${DEFAULT_SIGN_INTERVAL})").withRequiredArg().ofType(Long::class.java).defaultsTo(DEFAULT_SIGN_INTERVAL)
|
|
||||||
accepts("initialNetworkParameters", "initial network parameters filepath").withRequiredArg().describedAs("The initial network map").describedAs("filepath")
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val configFile = if (argConfig.hasPath("configFile")) {
|
/**
|
||||||
Paths.get(argConfig.getString("configFile"))
|
* Parses the doorman command line options.
|
||||||
} else {
|
*/
|
||||||
Paths.get(argConfig.getString("basedir")) / "node.conf"
|
fun parseCommandLine(vararg args: String): CommandLineOptions {
|
||||||
|
val optionParser = OptionParser()
|
||||||
|
val configFileArg = optionParser
|
||||||
|
.accepts("config-file", "The path to the config file")
|
||||||
|
.withRequiredArg()
|
||||||
|
.describedAs("filepath")
|
||||||
|
val initialNetworkParametersArg = optionParser
|
||||||
|
.accepts("initial-network-parameters", "initial network parameters filepath")
|
||||||
|
.withRequiredArg()
|
||||||
|
.describedAs("The initial network map")
|
||||||
|
.describedAs("filepath")
|
||||||
|
val helpOption = optionParser.acceptsAll(listOf("h", "?", "help"), "show help").forHelp();
|
||||||
|
|
||||||
|
val optionSet = optionParser.parse(*args)
|
||||||
|
// Print help and exit on help option.
|
||||||
|
if (optionSet.has(helpOption)) {
|
||||||
|
throw ShowHelpException(optionParser)
|
||||||
}
|
}
|
||||||
return argConfig.withFallback(ConfigFactory.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true)))
|
val configFile = Paths.get(optionSet.valueOf(configFileArg)).toAbsolutePath()
|
||||||
|
val initialNetworkParameters = Paths.get(optionSet.valueOf(initialNetworkParametersArg)).toAbsolutePath()
|
||||||
|
|
||||||
|
return CommandLineOptions(configFile, initialNetworkParameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a configuration file, which contains all the configuration except the initial values for the network
|
||||||
|
* parameters.
|
||||||
|
*/
|
||||||
|
fun parseParameters(configFile: Path): DoormanParameters {
|
||||||
|
return ConfigFactory
|
||||||
|
.parseFile(configFile.toFile(), ConfigParseOptions.defaults().setAllowMissing(true))
|
||||||
.resolve()
|
.resolve()
|
||||||
.parseAs()
|
.parseAs()
|
||||||
}
|
}
|
||||||
|
@ -245,8 +245,8 @@ private class ApproveAllCertificateRequestStorage(private val delegate: Certific
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
try {
|
try {
|
||||||
// TODO : Remove config overrides and solely use config file after testnet is finalized.
|
val commandLineOptions = parseCommandLine(*args)
|
||||||
parseParameters(*args).run {
|
parseParameters(commandLineOptions.configFile).run {
|
||||||
when (mode) {
|
when (mode) {
|
||||||
DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair(
|
DoormanParameters.Mode.ROOT_KEYGEN -> generateRootKeyPair(
|
||||||
rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
rootStorePath ?: throw IllegalArgumentException("The 'rootStorePath' parameter must be specified when generating keys!"),
|
||||||
@ -263,7 +263,7 @@ fun main(args: Array<String>) {
|
|||||||
val database = configureDatabase(dataSourceProperties, databaseProperties, { throw UnsupportedOperationException() }, SchemaService())
|
val database = configureDatabase(dataSourceProperties, databaseProperties, { throw UnsupportedOperationException() }, SchemaService())
|
||||||
val signer = buildLocalSigner(this)
|
val signer = buildLocalSigner(this)
|
||||||
|
|
||||||
val networkParameters = parseNetworkParametersFrom(initialNetworkParameters)
|
val networkParameters = parseNetworkParametersFrom(commandLineOptions.initialNetworkParameters)
|
||||||
startDoorman(NetworkHostAndPort(host, port), database, approveAll, networkParameters, signer, approveInterval, signInterval, jiraConfig)
|
startDoorman(NetworkHostAndPort(host, port), database, approveAll, networkParameters, signer, approveInterval, signInterval, jiraConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,52 @@
|
|||||||
package com.r3.corda.networkmanage.doorman
|
package com.r3.corda.networkmanage.doorman
|
||||||
|
|
||||||
import com.r3.corda.networkmanage.TestBase
|
import com.r3.corda.networkmanage.common.utils.ShowHelpException
|
||||||
import com.typesafe.config.ConfigException
|
import com.typesafe.config.ConfigException
|
||||||
import net.corda.core.utilities.seconds
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Paths
|
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
|
||||||
class DoormanParametersTest : TestBase() {
|
class DoormanParametersTest {
|
||||||
private val testDummyPath = ".${File.separator}testDummyPath.jks"
|
|
||||||
private val validInitialNetworkConfigPath = File(javaClass.getResource("/initial-network-parameters.conf").toURI()).absolutePath
|
private val validInitialNetworkConfigPath = File(javaClass.getResource("/initial-network-parameters.conf").toURI()).absolutePath
|
||||||
private val validConfigPath = File(javaClass.getResource("/doorman.conf").toURI()).absolutePath
|
private val validConfigPath = File(javaClass.getResource("/doorman.conf").toURI()).absolutePath
|
||||||
private val invalidConfigPath = File(javaClass.getResource("/doorman_fail.conf").toURI()).absolutePath
|
private val invalidConfigPath = File(javaClass.getResource("/doorman_fail.conf").toURI()).absolutePath
|
||||||
|
private val validArgs = arrayOf("--config-file", validConfigPath, "--initial-network-parameters", validInitialNetworkConfigPath)
|
||||||
private val requiredArgs = arrayOf("--configFile", validConfigPath, "--initialNetworkParameters", validInitialNetworkConfigPath)
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `parse mode flag arg correctly`() {
|
fun `should fail when initial network parameters file is missing`() {
|
||||||
assertEquals(DoormanParameters.Mode.CA_KEYGEN, callParseParametersWithRequiredArgs("--mode", "CA_KEYGEN").mode)
|
val message = assertFailsWith<IllegalStateException> {
|
||||||
assertEquals(DoormanParameters.Mode.ROOT_KEYGEN, callParseParametersWithRequiredArgs("--mode", "ROOT_KEYGEN").mode)
|
parseCommandLine("--config-file", validConfigPath, "--initial-network-parameters", "not-here")
|
||||||
assertEquals(DoormanParameters.Mode.DOORMAN, callParseParametersWithRequiredArgs("--mode", "DOORMAN").mode)
|
}.message
|
||||||
|
assertThat(message).contains("Initial network parameters file ")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `command line arg should override config file`() {
|
fun `should fail when config file is missing`() {
|
||||||
val params = callParseParametersWithRequiredArgs("--keystorePath", testDummyPath, "--port", "1000")
|
val message = assertFailsWith<IllegalStateException> {
|
||||||
assertEquals(testDummyPath, params.keystorePath.toString())
|
parseCommandLine("--config-file", "not-existing-file", "--initial-network-parameters", validInitialNetworkConfigPath)
|
||||||
assertEquals(1000, params.port)
|
}.message
|
||||||
|
assertThat(message).contains("Config file ")
|
||||||
|
}
|
||||||
|
|
||||||
val params2 = callParseParametersWithRequiredArgs()
|
@Test
|
||||||
assertEquals(Paths.get("/opt/doorman/certificates/caKeystore.jks"), params2.keystorePath)
|
fun `should throw ShowHelpException when -? is on the command line`() {
|
||||||
assertEquals(8080, params2.port)
|
assertFailsWith<ShowHelpException> {
|
||||||
|
parseCommandLine("-?")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should fail when config missing`() {
|
fun `should fail when config missing`() {
|
||||||
// dataSourceProperties is missing from node_fail.conf and it should fail during parsing, and shouldn't use default from reference.conf.
|
|
||||||
assertFailsWith<ConfigException.Missing> {
|
assertFailsWith<ConfigException.Missing> {
|
||||||
parseParameters("--configFile", invalidConfigPath)
|
parseParameters(parseCommandLine("--config-file", invalidConfigPath, "--initial-network-parameters", validInitialNetworkConfigPath).configFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `should parse jira config correctly`() {
|
fun `should parse jira config correctly`() {
|
||||||
val parameter = callParseParametersWithRequiredArgs()
|
val parameter = parseCommandLineAndGetParameters()
|
||||||
assertEquals("https://doorman-jira-host.com/", parameter.jiraConfig?.address)
|
assertEquals("https://doorman-jira-host.com/", parameter.jiraConfig?.address)
|
||||||
assertEquals("TD", parameter.jiraConfig?.projectCode)
|
assertEquals("TD", parameter.jiraConfig?.projectCode)
|
||||||
assertEquals("username", parameter.jiraConfig?.username)
|
assertEquals("username", parameter.jiraConfig?.username)
|
||||||
@ -53,7 +54,7 @@ class DoormanParametersTest : TestBase() {
|
|||||||
assertEquals(41, parameter.jiraConfig?.doneTransitionCode)
|
assertEquals(41, parameter.jiraConfig?.doneTransitionCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun callParseParametersWithRequiredArgs(vararg additionalArgs: String): DoormanParameters {
|
private fun parseCommandLineAndGetParameters(): DoormanParameters {
|
||||||
return parseParameters(*(requiredArgs + additionalArgs))
|
return parseParameters(parseCommandLine(*validArgs).configFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
basedir="."
|
||||||
keystorePath = "/opt/doorman/certificates/caKeystore.jks"
|
keystorePath = "/opt/doorman/certificates/caKeystore.jks"
|
||||||
keyStorePassword = "password"
|
keyStorePassword = "password"
|
||||||
caPrivateKeyPassword = "password"
|
caPrivateKeyPassword = "password"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user