mirror of
https://github.com/corda/corda.git
synced 2025-01-31 00:24:59 +00:00
CORDA-2450 Creating attachment version from whitelisted JARs fails for node upgrade (#4593)
Upgrade from node 3.0 to 4.0 fails to create versions of whitelisted JARs from networkParameters - read parameters from file at first as in Corda 3.0 there no relevant table, then try from the table. As this is migration, the code will run only once on each node, she increased log level to info for messages. Tested using https://r3-cev.atlassian.net/browse/R3T-1549
This commit is contained in:
parent
d95c68c2ae
commit
26cfea202b
@ -5,10 +5,16 @@ import liquibase.database.Database
|
|||||||
import liquibase.database.jvm.JdbcConnection
|
import liquibase.database.jvm.JdbcConnection
|
||||||
import liquibase.exception.ValidationErrors
|
import liquibase.exception.ValidationErrors
|
||||||
import liquibase.resource.ResourceAccessor
|
import liquibase.resource.ResourceAccessor
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.readObject
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.services.AttachmentId
|
|
||||||
import net.corda.core.serialization.deserialize
|
import net.corda.core.serialization.deserialize
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
|
import net.corda.nodeapi.internal.network.NETWORK_PARAMS_FILE_NAME
|
||||||
|
import net.corda.nodeapi.internal.network.SignedNetworkParameters
|
||||||
|
import net.corda.nodeapi.internal.persistence.SchemaMigration.Companion.NODE_BASE_DIR_KEY
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
|
||||||
class AttachmentVersionNumberMigration : CustomTaskChange {
|
class AttachmentVersionNumberMigration : CustomTaskChange {
|
||||||
companion object {
|
companion object {
|
||||||
@ -17,40 +23,49 @@ class AttachmentVersionNumberMigration : CustomTaskChange {
|
|||||||
|
|
||||||
override fun execute(database: Database?) {
|
override fun execute(database: Database?) {
|
||||||
val connection = database?.connection as JdbcConnection
|
val connection = database?.connection as JdbcConnection
|
||||||
|
val msg = "Attachment version creation from whitelisted JARs"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
logger.debug("Start executing...")
|
logger.info("Start executing...")
|
||||||
val networkParameters = getNetworkParameters(connection)
|
var networkParameters: NetworkParameters?
|
||||||
if (networkParameters == null) {
|
|
||||||
logger.debug("Network parameters not found.")
|
if (System.getProperty(NODE_BASE_DIR_KEY).isNotEmpty()) {
|
||||||
return
|
val path = Paths.get(System.getProperty(NODE_BASE_DIR_KEY)) / NETWORK_PARAMS_FILE_NAME
|
||||||
|
networkParameters = getNetworkParametersFromFile(path)
|
||||||
|
if (networkParameters != null) {
|
||||||
|
logger.info("$msg using network parameters from $path, whitelistedContractImplementations: ${networkParameters.whitelistedContractImplementations}.")
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Network parameters epoch: ${networkParameters.epoch}, whitelistedContractImplementations: ${networkParameters.whitelistedContractImplementations}.")
|
logger.warn("$msg skipped, network parameters not found in $path.")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.error("$msg skipped, network parameters not retrieved, could not determine node base directory due to system property $NODE_BASE_DIR_KEY being not set.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val availableAttachments = getAttachmentsWithDefaultVersion(connection)
|
val availableAttachments = getAttachmentsWithDefaultVersion(connection)
|
||||||
if (availableAttachments.isEmpty()) {
|
if (availableAttachments.isEmpty()) {
|
||||||
logger.debug("Attachments not found.")
|
logger.info("$msg skipped, no attachments not found.")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Attachments with version '1': $availableAttachments")
|
logger.info("$msg, candidate attachments with version '1': $availableAttachments")
|
||||||
}
|
}
|
||||||
|
|
||||||
availableAttachments.forEach { attachmentId ->
|
availableAttachments.forEach { attachmentId ->
|
||||||
val versions = networkParameters?.whitelistedContractImplementations?.values.mapNotNull { it.indexOfFirst { it.toString() == attachmentId} }.filter { it >= 0 }
|
val versions = networkParameters?.whitelistedContractImplementations?.values.mapNotNull { it.indexOfFirst { it.toString() == attachmentId } }.filter { it >= 0 }
|
||||||
val maxPosition = versions.max() ?: 0
|
val maxPosition = versions.max() ?: 0
|
||||||
if (maxPosition > 0) {
|
if (maxPosition > 0) {
|
||||||
val version = maxPosition + 1
|
val version = maxPosition + 1
|
||||||
val msg = "Updating version of attachment $attachmentId to '$version'"
|
val msg = "Updating version of attachment $attachmentId to '$version'."
|
||||||
if (versions.toSet().size > 1)
|
if (versions.toSet().size > 1)
|
||||||
logger.warn("Several versions based on whitelistedContractImplementations position are available: ${versions.toSet()}. $msg")
|
logger.warn("Several versions based on whitelistedContractImplementations position are available: ${versions.toSet()}. $msg")
|
||||||
else
|
else
|
||||||
logger.debug(msg)
|
logger.info(msg)
|
||||||
updateVersion(connection, attachmentId, version)
|
updateVersion(connection, attachmentId, version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Done")
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logger.error("Exception while retrieving network parameters ${e.message}", e)
|
logger.error("$msg exception ${e.message}", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,16 +83,9 @@ class AttachmentVersionNumberMigration : CustomTaskChange {
|
|||||||
override fun setUp() {
|
override fun setUp() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNetworkParameters(connection: JdbcConnection): NetworkParameters? =
|
private fun getNetworkParametersFromFile(path: Path): NetworkParameters? {
|
||||||
connection.createStatement().use {
|
val networkParametersBytes = path?.readObject<SignedNetworkParameters>()
|
||||||
val rs = it.executeQuery("SELECT PARAMETERS_BYTES FROM NODE_NETWORK_PARAMETERS ORDER BY EPOCH DESC")
|
return networkParametersBytes?.raw?.deserialize()
|
||||||
if (rs.next()) {
|
|
||||||
val networkParametersBytes = rs.getBytes(1) as ByteArray
|
|
||||||
val networkParameters: NetworkParameters = networkParametersBytes.deserialize()
|
|
||||||
rs.close()
|
|
||||||
networkParameters
|
|
||||||
} else
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getAttachmentsWithDefaultVersion(connection: JdbcConnection): List<String> =
|
private fun getAttachmentsWithDefaultVersion(connection: JdbcConnection): List<String> =
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.core.schemas.MappedSchema
|
|||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.nio.file.Path
|
||||||
import java.sql.Statement
|
import java.sql.Statement
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
|
|
||||||
@ -20,10 +21,12 @@ class SchemaMigration(
|
|||||||
val schemas: Set<MappedSchema>,
|
val schemas: Set<MappedSchema>,
|
||||||
val dataSource: DataSource,
|
val dataSource: DataSource,
|
||||||
private val databaseConfig: DatabaseConfig,
|
private val databaseConfig: DatabaseConfig,
|
||||||
private val classLoader: ClassLoader = Thread.currentThread().contextClassLoader) {
|
private val classLoader: ClassLoader = Thread.currentThread().contextClassLoader,
|
||||||
|
private val currentDirectory: Path?) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = contextLogger()
|
private val logger = contextLogger()
|
||||||
|
const val NODE_BASE_DIR_KEY = "liquibase.nodeDaseDir"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +89,8 @@ class SchemaMigration(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.setProperty(NODE_BASE_DIR_KEY, currentDirectory.toString()) // base dir for any custom change set which may need to load a file (currently AttachmentVersionNumberMigration)
|
||||||
|
|
||||||
val customResourceAccessor = CustomResourceAccessor(dynamicInclude, changelogList, classLoader)
|
val customResourceAccessor = CustomResourceAccessor(dynamicInclude, changelogList, classLoader)
|
||||||
|
|
||||||
val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection)))
|
val liquibase = Liquibase(dynamicInclude, customResourceAccessor, getLiquibaseDatabase(JdbcConnection(connection)))
|
||||||
|
@ -90,6 +90,7 @@ import rx.Observable
|
|||||||
import rx.Scheduler
|
import rx.Scheduler
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.nio.file.Path
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.security.KeyStoreException
|
import java.security.KeyStoreException
|
||||||
@ -778,7 +779,7 @@ abstract class AbstractNode<S>(val configuration: NodeConfiguration,
|
|||||||
protected open fun startDatabase() {
|
protected open fun startDatabase() {
|
||||||
val props = configuration.dataSourceProperties
|
val props = configuration.dataSourceProperties
|
||||||
if (props.isEmpty) throw DatabaseConfigurationException("There must be a database configured.")
|
if (props.isEmpty) throw DatabaseConfigurationException("There must be a database configured.")
|
||||||
database.startHikariPool(props, configuration.database, schemaService.internalSchemas(), metricRegistry, this.cordappLoader.appClassLoader)
|
database.startHikariPool(props, configuration.database, schemaService.internalSchemas(), metricRegistry, this.cordappLoader.appClassLoader, configuration.baseDirectory)
|
||||||
// Now log the vendor string as this will also cause a connection to be tested eagerly.
|
// Now log the vendor string as this will also cause a connection to be tested eagerly.
|
||||||
logVendorString(database, log)
|
logVendorString(database, log)
|
||||||
}
|
}
|
||||||
@ -1090,10 +1091,10 @@ fun createCordaPersistence(databaseConfig: DatabaseConfig,
|
|||||||
return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, jdbcUrl, cacheFactory, attributeConverters, customClassLoader)
|
return CordaPersistence(databaseConfig, schemaService.schemaOptions.keys, jdbcUrl, cacheFactory, attributeConverters, customClassLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>, metricRegistry: MetricRegistry? = null, classloader: ClassLoader = Thread.currentThread().contextClassLoader) {
|
fun CordaPersistence.startHikariPool(hikariProperties: Properties, databaseConfig: DatabaseConfig, schemas: Set<MappedSchema>, metricRegistry: MetricRegistry? = null, classloader: ClassLoader = Thread.currentThread().contextClassLoader, currentDir: Path? = null) {
|
||||||
try {
|
try {
|
||||||
val dataSource = DataSourceFactory.createDataSource(hikariProperties, metricRegistry = metricRegistry)
|
val dataSource = DataSourceFactory.createDataSource(hikariProperties, metricRegistry = metricRegistry)
|
||||||
val schemaMigration = SchemaMigration(schemas, dataSource, databaseConfig, classloader)
|
val schemaMigration = SchemaMigration(schemas, dataSource, databaseConfig, classloader, currentDir)
|
||||||
schemaMigration.nodeStartup(dataSource.connection.use { DBCheckpointStorage().getCheckpointCount(it) != 0L })
|
schemaMigration.nodeStartup(dataSource.connection.use { DBCheckpointStorage().getCheckpointCount(it) != 0L })
|
||||||
start(dataSource)
|
start(dataSource)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user