Merge branch 'master' of https://github.com/corda/corda into christians_checkpoint_checker_thread

# Conflicts:
#	node/src/main/kotlin/net/corda/node/services/config/NodeConfiguration.kt
#	node/src/test/kotlin/net/corda/node/services/config/FullNodeConfigurationTest.kt
This commit is contained in:
Christian Sailer 2017-10-27 15:33:00 +01:00
commit 862b908dd9
12 changed files with 82 additions and 100 deletions

View File

@ -1,8 +1,7 @@
package net.corda.docs
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.nodeapi.config.parseAs
import net.corda.node.services.config.parseAsNodeConfiguration
import net.corda.verifier.Verifier
import org.junit.Test
import java.nio.file.Path
@ -34,7 +33,7 @@ class ExampleConfigTest {
ConfigHelper.loadConfig(
baseDirectory = baseDirectory,
configFile = it
).parseAs<FullNodeConfiguration>()
).parseAsNodeConfiguration()
}
}

View File

@ -4,8 +4,7 @@ import joptsimple.OptionParser
import joptsimple.util.EnumConverter
import net.corda.core.internal.div
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.nodeapi.config.parseAs
import net.corda.node.services.config.parseAsNodeConfiguration
import org.slf4j.event.Level
import java.io.PrintStream
import java.nio.file.Path
@ -71,6 +70,5 @@ data class CmdLineOptions(val baseDirectory: Path,
val sshdServer: Boolean,
val justGenerateNodeInfo: Boolean) {
fun loadConfig() = ConfigHelper
.loadConfig(baseDirectory, configFile)
.parseAs<FullNodeConfiguration>()
.loadConfig(baseDirectory, configFile).parseAsNodeConfiguration()
}

View File

@ -22,7 +22,6 @@ import net.corda.node.services.RPCUserService
import net.corda.node.services.RPCUserServiceImpl
import net.corda.node.services.api.NetworkMapCacheInternal
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.ArtemisMessagingServer.Companion.ipDetectRequestProperty
@ -62,7 +61,7 @@ import kotlin.system.exitProcess
*
* @param configuration This is typically loaded from a TypeSafe HOCON configuration file.
*/
open class Node(configuration: FullNodeConfiguration,
open class Node(override val configuration: NodeConfiguration,
versionInfo: VersionInfo,
val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration)
@ -84,7 +83,7 @@ open class Node(configuration: FullNodeConfiguration,
exitProcess(1)
}
private fun createClock(configuration: FullNodeConfiguration): Clock {
private fun createClock(configuration: NodeConfiguration): Clock {
return if (configuration.useTestClock) TestClock() else NodeClock()
}
@ -99,7 +98,6 @@ open class Node(configuration: FullNodeConfiguration,
}
override val log: Logger get() = logger
override val configuration get() = super.configuration as FullNodeConfiguration // Necessary to avoid init order NPE.
override val networkMapAddress: NetworkMapAddress? get() = configuration.networkMapService?.address?.let(::NetworkMapAddress)
override fun makeTransactionVerifierService() = (network as NodeMessagingClient).verifierService
@ -153,14 +151,8 @@ open class Node(configuration: FullNodeConfiguration,
override fun makeMessagingService(legalIdentity: PartyAndCertificate): MessagingService {
userService = RPCUserServiceImpl(configuration.rpcUsers)
val (serverAddress, advertisedAddress) = with(configuration) {
if (messagingServerAddress != null) {
// External broker
messagingServerAddress to messagingServerAddress
} else {
makeLocalMessageBroker() to getAdvertisedAddress()
}
}
val serverAddress = configuration.messagingServerAddress ?: makeLocalMessageBroker()
val advertisedAddress = configuration.messagingServerAddress ?: getAdvertisedAddress()
printBasicNodeInfo("Incoming connection address", advertisedAddress.toString())

View File

@ -7,7 +7,7 @@ import net.corda.core.internal.*
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.utilities.loggerFor
import net.corda.node.*
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.transactions.bftSMaRtSerialFilter
import net.corda.node.shell.InteractiveShell
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
@ -84,11 +84,11 @@ open class NodeStartup(val args: Array<String>) {
exitProcess(0)
}
open protected fun preNetworkRegistration(conf: FullNodeConfiguration) = Unit
open protected fun preNetworkRegistration(conf: NodeConfiguration) = Unit
open protected fun createNode(conf: FullNodeConfiguration, versionInfo: VersionInfo): Node = Node(conf, versionInfo)
open protected fun createNode(conf: NodeConfiguration, versionInfo: VersionInfo): Node = Node(conf, versionInfo)
open protected fun startNode(conf: FullNodeConfiguration, versionInfo: VersionInfo, startTime: Long, cmdlineOptions: CmdLineOptions) {
open protected fun startNode(conf: NodeConfiguration, versionInfo: VersionInfo, startTime: Long, cmdlineOptions: CmdLineOptions) {
val node = createNode(conf, versionInfo)
if (cmdlineOptions.justGenerateNodeInfo) {
// Perform the minimum required start-up logic to be able to write a nodeInfo to disk
@ -118,14 +118,14 @@ open class NodeStartup(val args: Array<String>) {
startedNode.internals.run()
}
open protected fun logStartupInfo(versionInfo: VersionInfo, cmdlineOptions: CmdLineOptions, conf: FullNodeConfiguration) {
open protected fun logStartupInfo(versionInfo: VersionInfo, cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {
logger.info("Vendor: ${versionInfo.vendor}")
logger.info("Release: ${versionInfo.releaseVersion}")
logger.info("Platform Version: ${versionInfo.platformVersion}")
logger.info("Revision: ${versionInfo.revision}")
val info = ManagementFactory.getRuntimeMXBean()
logger.info("PID: ${info.name.split("@").firstOrNull()}") // TODO Java 9 has better support for this
logger.info("Main class: ${FullNodeConfiguration::class.java.protectionDomain.codeSource.location.toURI().path}")
logger.info("Main class: ${NodeConfiguration::class.java.protectionDomain.codeSource.location.toURI().path}")
logger.info("CommandLine Args: ${info.inputArguments.joinToString(" ")}")
logger.info("Application Args: ${args.joinToString(" ")}")
logger.info("bootclasspath: ${info.bootClassPath}")
@ -140,7 +140,7 @@ open class NodeStartup(val args: Array<String>) {
logger.info("Starting as node on ${conf.p2pAddress}")
}
open protected fun maybeRegisterWithNetworkAndExit(cmdlineOptions: CmdLineOptions, conf: FullNodeConfiguration) {
open protected fun maybeRegisterWithNetworkAndExit(cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {
if (!cmdlineOptions.isRegistration) return
println()
println("******************************************************************")
@ -152,7 +152,7 @@ open class NodeStartup(val args: Array<String>) {
exitProcess(0)
}
open protected fun loadConfigFile(cmdlineOptions: CmdLineOptions): FullNodeConfiguration {
open protected fun loadConfigFile(cmdlineOptions: CmdLineOptions): NodeConfiguration {
try {
return cmdlineOptions.loadConfig()
} catch (e: ConfigException) {
@ -161,7 +161,7 @@ open class NodeStartup(val args: Array<String>) {
}
}
open protected fun banJavaSerialisation(conf: FullNodeConfiguration) {
open protected fun banJavaSerialisation(conf: NodeConfiguration) {
SerialFilter.install(if (conf.notary?.bftSMaRt != null) ::bftSMaRtSerialFilter else ::defaultSerialFilter)
}

View File

@ -18,6 +18,12 @@ interface RPCUserService {
// TODO Or ditch this and consider something like Apache Shiro
// TODO Need access to permission checks from inside flows and at other point during audit checking.
class RPCUserServiceImpl(override val users: List<User>) : RPCUserService {
init {
users.forEach {
require(it.username.matches("\\w+".toRegex())) { "Username ${it.username} contains invalid characters" }
}
}
override fun getUser(username: String): User? = users.find { it.username == username }
}

View File

@ -1,5 +1,6 @@
package net.corda.node.services.config
import com.typesafe.config.Config
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.seconds
@ -7,6 +8,7 @@ import net.corda.node.internal.NetworkMapInfo
import net.corda.node.services.messaging.CertificateChainCheckPolicy
import net.corda.nodeapi.User
import net.corda.nodeapi.config.NodeSSLConfiguration
import net.corda.nodeapi.config.parseAs
import java.net.URL
import java.nio.file.Path
import java.util.*
@ -38,10 +40,12 @@ interface NodeConfiguration : NodeSSLConfiguration {
val notary: NotaryConfig?
val activeMQServer: ActiveMqServerConfiguration
val additionalNodeInfoPollingFrequencyMsec: Long
companion object {
const val DISABLE_CHECKPOINT_CHECKER = "disableCheckpointChecker"
}
val useHTTPS: Boolean
val p2pAddress: NetworkHostAndPort
val rpcAddress: NetworkHostAndPort?
val messagingServerAddress: NetworkHostAndPort?
val useTestClock: Boolean get() = false
val detectPublicIp: Boolean get() = true
}
data class NotaryConfig(val validating: Boolean,
@ -75,7 +79,14 @@ data class BridgeConfiguration(val retryIntervalMs: Long,
data class ActiveMqServerConfiguration(val bridge: BridgeConfiguration)
data class FullNodeConfiguration(
fun Config.parseAsNodeConfiguration(): NodeConfiguration = this.parseAs<NodeConfigurationImpl>()
/**
* Implementation of [NodeConfiguration]
* This should be private but it can't because its constructor needs to be invoked reflectively by [parseAs] and
* kotlin doesn't allow that.
*/
data class NodeConfigurationImpl(
/** This is not retrieved from the config file but rather from a command line argument. */
override val baseDirectory: Path,
override val myLegalName: CordaX500Name,
@ -91,18 +102,18 @@ data class FullNodeConfiguration(
override val rpcUsers: List<User>,
override val verifierType: VerifierType,
override val messageRedeliveryDelaySeconds: Int = 30,
val useHTTPS: Boolean,
val p2pAddress: NetworkHostAndPort,
val rpcAddress: NetworkHostAndPort?,
override val useHTTPS: Boolean,
override val p2pAddress: NetworkHostAndPort,
override val rpcAddress: NetworkHostAndPort?,
// TODO This field is slightly redundant as p2pAddress is sufficient to hold the address of the node's MQ broker.
// Instead this should be a Boolean indicating whether that broker is an internal one started by the node or an external one
val messagingServerAddress: NetworkHostAndPort?,
override val messagingServerAddress: NetworkHostAndPort?,
override val notary: NotaryConfig?,
override val certificateChainCheckPolicies: List<CertChainPolicyConfig>,
override val devMode: Boolean = false,
override val devModeOptions: DevModeOptions? = null,
val useTestClock: Boolean = false,
val detectPublicIp: Boolean = true,
override val useTestClock: Boolean = false,
override val detectPublicIp: Boolean = true,
override val activeMQServer: ActiveMqServerConfiguration,
override val additionalNodeInfoPollingFrequencyMsec: Long = 5.seconds.toMillis()
) : NodeConfiguration {
@ -112,10 +123,6 @@ data class FullNodeConfiguration(
// This is a sanity feature do not remove.
require(!useTestClock || devMode) { "Cannot use test clock outside of dev mode" }
require(devModeOptions == null || devMode) { "Cannot use devModeOptions outside of dev mode" }
// TODO Move this to ArtemisMessagingServer
rpcUsers.forEach {
require(it.username.matches("\\w+".toRegex())) { "Username ${it.username} contains invalid characters" }
}
require(myLegalName.commonName == null) { "Common name must be null: $myLegalName" }
require(minimumPlatformVersion >= 1) { "minimumPlatformVersion cannot be less than 1" }
}

View File

@ -0,0 +1,20 @@
package net.corda.node.services
import net.corda.nodeapi.User
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
class RPCUserServiceTest {
@Test
fun `Artemis special characters not permitted in RPC usernames`() {
assertThatThrownBy { configWithRPCUsername("user.1") }.hasMessageContaining(".")
assertThatThrownBy { configWithRPCUsername("user*1") }.hasMessageContaining("*")
assertThatThrownBy { configWithRPCUsername("user#1") }.hasMessageContaining("#")
}
private fun configWithRPCUsername(username: String) {
RPCUserServiceImpl(listOf(User(username, "password", setOf())))
}
}

View File

@ -13,42 +13,10 @@ import java.nio.file.Paths
import java.util.*
import kotlin.test.assertFalse
class FullNodeConfigurationTest {
class NodeConfigurationImplTest {
@Test
fun `Artemis special characters not permitted in RPC usernames`() {
val testConfiguration = FullNodeConfiguration(
baseDirectory = Paths.get("."),
myLegalName = ALICE.name,
networkMapService = null,
emailAddress = "",
keyStorePassword = "cordacadevpass",
trustStorePassword = "trustpass",
dataSourceProperties = makeTestDataSourceProperties(ALICE.name.organisation),
database = makeTestDatabaseProperties(),
certificateSigningService = URL("http://localhost"),
rpcUsers = emptyList(),
verifierType = VerifierType.InMemory,
useHTTPS = false,
p2pAddress = NetworkHostAndPort("localhost", 0),
rpcAddress = NetworkHostAndPort("localhost", 1),
messagingServerAddress = null,
notary = null,
certificateChainCheckPolicies = emptyList(),
devMode = true,
activeMQServer = ActiveMqServerConfiguration(BridgeConfiguration(0, 0, 0.0)),
additionalNodeInfoPollingFrequencyMsec = 5.seconds.toMillis())
fun configWithRPCUsername(username: String) {
testConfiguration.copy(rpcUsers = listOf(User(username, "pass", emptySet())))
}
assertThatThrownBy { configWithRPCUsername("user.1") }.hasMessageContaining(".")
assertThatThrownBy { configWithRPCUsername("user*1") }.hasMessageContaining("*")
assertThatThrownBy { configWithRPCUsername("user#1") }.hasMessageContaining("#")
}
@Test
fun `Can't have debug options if not in dev mode`() {
val testConfiguration = FullNodeConfiguration(
fun `Can't have dev mode options if not in dev mode`() {
val testConfiguration = NodeConfigurationImpl(
baseDirectory = Paths.get("."),
myLegalName = ALICE.name,
networkMapService = null,
@ -83,7 +51,7 @@ class FullNodeConfigurationTest {
@Test
fun `check devModeOptions flag helper`()
{
val testConfiguration = FullNodeConfiguration(
val testConfiguration = NodeConfigurationImpl(
baseDirectory = Paths.get("."),
myLegalName = ALICE.name,
networkMapService = null,

View File

@ -19,14 +19,10 @@ import net.corda.core.utilities.seconds
import net.corda.finance.plugin.registerFinanceJSONMappers
import net.corda.irs.contract.InterestRateSwap
import net.corda.irs.web.IrsDemoWebApplication
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.User
import net.corda.test.spring.springDriver
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.IntegrationTestCategory
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.http.HttpApi
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat
@ -96,7 +92,7 @@ class IRSDemoTest : IntegrationTestCategory {
fun getFloatingLegFixCount(nodeApi: HttpApi) = getTrades(nodeApi)[0].calculation.floatingLegPaymentSchedule.count { it.value.rate.ratioUnit != null }
private fun getFixingDateObservable(config: FullNodeConfiguration): Observable<LocalDate?> {
private fun getFixingDateObservable(config: NodeConfiguration): Observable<LocalDate?> {
val client = CordaRPCClient(config.rpcAddress!!)
val proxy = client.start("user", "password").proxy
val vaultUpdates = proxy.vaultTrackBy<InterestRateSwap.State>().updates

View File

@ -31,7 +31,6 @@ import net.corda.node.services.network.NetworkMapService
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.NodeInfoFilesCopier
import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.testing.*
@ -198,13 +197,13 @@ sealed class NodeHandle {
* will be added and that will be used.
*/
abstract val rpc: CordaRPCOps
abstract val configuration: FullNodeConfiguration
abstract val configuration: NodeConfiguration
abstract val webAddress: NetworkHostAndPort
data class OutOfProcess(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: FullNodeConfiguration,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
val debugPort: Int?,
val process: Process,
@ -223,7 +222,7 @@ sealed class NodeHandle {
data class InProcess(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: FullNodeConfiguration,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
val node: StartedNode<Node>,
val nodeThread: Thread,
@ -697,7 +696,7 @@ class DriverDSL(
_executorService?.shutdownNow()
}
private fun establishRpc(config: FullNodeConfiguration, processDeathFuture: CordaFuture<out Process>): CordaFuture<CordaRPCOps> {
private fun establishRpc(config: NodeConfiguration, processDeathFuture: CordaFuture<out Process>): CordaFuture<CordaRPCOps> {
val rpcAddress = config.rpcAddress!!
val client = CordaRPCClient(rpcAddress)
val connectionFuture = poll(executorService, "RPC connection") {
@ -913,7 +912,7 @@ class DriverDSL(
}
private fun startNodeInternal(config: Config, webAddress: NetworkHostAndPort, startInProcess: Boolean?, maximumHeapSize: String): CordaFuture<NodeHandle> {
val nodeConfiguration = config.parseAs<FullNodeConfiguration>()
val nodeConfiguration = config.parseAsNodeConfiguration()
nodeInfoFilesCopier.addConfig(nodeConfiguration.baseDirectory)
val onNodeExit: () -> Unit = {
nodeInfoFilesCopier.removeConfig(nodeConfiguration.baseDirectory)
@ -983,7 +982,7 @@ class DriverDSL(
private fun startInProcessNode(
executorService: ScheduledExecutorService,
nodeConf: FullNodeConfiguration,
nodeConf: NodeConfiguration,
config: Config,
cordappPackages: List<String>
): CordaFuture<Pair<StartedNode<Node>, Thread>> {
@ -1002,7 +1001,7 @@ class DriverDSL(
private fun startOutOfProcessNode(
executorService: ScheduledExecutorService,
nodeConf: FullNodeConfiguration,
nodeConf: NodeConfiguration,
config: Config,
quasarJarPath: String,
debugPort: Int?,

View File

@ -13,7 +13,6 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.config.*
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.testing.DUMMY_MAP
import net.corda.testing.TestDependencyInjectionBase
@ -190,7 +189,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
) + configOverrides
)
val parsedConfig = config.parseAs<FullNodeConfiguration>()
val parsedConfig = config.parseAsNodeConfiguration()
val node = Node(
parsedConfig,
MOCK_VERSION_INFO.copy(platformVersion = platformVersion),

View File

@ -5,10 +5,8 @@ import com.typesafe.config.ConfigValueFactory
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.NetworkMapInfo
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.config.parseAsNodeConfiguration
import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.nodeapi.config.toConfig
import net.corda.testing.DUMMY_NOTARY
import net.corda.webserver.WebServerConfig
@ -43,7 +41,7 @@ class NodeConfigTest {
.withValue("baseDirectory", ConfigValueFactory.fromAnyRef(baseDir.toString()))
.withFallback(ConfigFactory.parseResources("reference.conf"))
.resolve()
val fullConfig = nodeConfig.parseAs<FullNodeConfiguration>()
val fullConfig = nodeConfig.parseAsNodeConfiguration()
assertEquals(myLegalName, fullConfig.myLegalName)
assertEquals(localPort(40002), fullConfig.rpcAddress)