CORE-10259: Update template to use CSDE plugin (#35)
* updated csde to use plugin * update csde block * update network file * allign to Kotlin csde * CORE-10259: Update template to use CSDE plugin --------- Co-authored-by: mattbradburyr3 <matthew.bradbury@r3.com>
This commit is contained in:
parent
a043d8dcd1
commit
2346e34494
3
.gitignore
vendored
3
.gitignore
vendored
@ -86,3 +86,6 @@ workspace/**
|
|||||||
#*.pfx
|
#*.pfx
|
||||||
#CPIFileStatus*.json
|
#CPIFileStatus*.json
|
||||||
#GroupPolicy.json
|
#GroupPolicy.json
|
||||||
|
|
||||||
|
# Ignore temporary data files
|
||||||
|
*.dat
|
35
build.gradle
35
build.gradle
@ -6,7 +6,7 @@ plugins {
|
|||||||
id 'org.jetbrains.kotlin.plugin.jpa'
|
id 'org.jetbrains.kotlin.plugin.jpa'
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'csde'
|
id 'net.corda.plugins.csde'
|
||||||
}
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
@ -15,6 +15,23 @@ allprojects {
|
|||||||
|
|
||||||
def javaVersion = VERSION_11
|
def javaVersion = VERSION_11
|
||||||
|
|
||||||
|
// Configure the CSDE
|
||||||
|
csde {
|
||||||
|
cordaClusterURL = "https://localhost:8888"
|
||||||
|
networkConfigFile = "config/static-network-config.json"
|
||||||
|
corDappCpiName = "MyCorDapp"
|
||||||
|
notaryCpiName = "NotaryServer"
|
||||||
|
cordaRpcUser = "admin"
|
||||||
|
cordaRpcPasswd ="admin"
|
||||||
|
csdeWorkspaceDir = "workspace"
|
||||||
|
notaryVersion = cordaNotaryPluginsVersion
|
||||||
|
combinedWorkerVersion = "5.0.0.0-Gecko1.0"
|
||||||
|
postgresJdbcVersion = "42.4.3"
|
||||||
|
cordaDbContainerName = "CSDEpostgresql"
|
||||||
|
cordaBinDir = "${System.getProperty("user.home")}/.corda/corda5"
|
||||||
|
cordaCliBinDir = "${System.getProperty("user.home")}/.corda/cli"
|
||||||
|
}
|
||||||
|
|
||||||
// Declare the set of Java compiler options we need to build a CorDapp.
|
// Declare the set of Java compiler options we need to build a CorDapp.
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
// -parameters - Needed for reflection and serialization to work correctly.
|
// -parameters - Needed for reflection and serialization to work correctly.
|
||||||
@ -25,9 +42,23 @@ allprojects {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
// All dependencies are held in Maven Central
|
// All dependencies are held in Maven Central
|
||||||
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
|
// R3 Internal repositories for dev
|
||||||
|
// Repository provides Corda 5 binaries that implement Corda-API.
|
||||||
|
// These will be made publicly available.
|
||||||
|
// Final location to be decided.
|
||||||
|
// Repository subject to change
|
||||||
maven {
|
maven {
|
||||||
url = "$artifactoryContextUrl/"
|
url = "$artifactoryContextUrl/corda-os-maven"
|
||||||
|
authentication {
|
||||||
|
basic(BasicAuthentication)
|
||||||
|
}
|
||||||
|
credentials {
|
||||||
|
username = findProperty('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
|
||||||
|
password = findProperty('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
|
|
||||||
plugins {
|
|
||||||
id 'groovy-gradle-plugin'
|
|
||||||
id 'java'
|
|
||||||
}
|
|
||||||
|
|
||||||
def constants = new Properties()
|
|
||||||
file("$rootDir/../gradle.properties").withInputStream { InputStream input -> constants.load(input) }
|
|
||||||
def artifactoryContextUrl = constants.getProperty('artifactoryContextUrl')
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
mavenLocal()
|
|
||||||
maven {
|
|
||||||
url = "$artifactoryContextUrl/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
|
||||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
|
||||||
|
|
||||||
implementation "com.konghq:unirest-java:$unirestVersion"
|
|
||||||
implementation "com.konghq:unirest-objectmapper-jackson:$unirestVersion"
|
|
||||||
implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
|
|
||||||
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion"
|
|
||||||
|
|
||||||
implementation "net.corda:corda-base:$cordaApiVersion"
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
jacksonVersion = 2.13.4
|
|
||||||
unirestVersion=3.13.10
|
|
||||||
|
|
||||||
cordaApiVersion=5.0.0.665-Gecko1.0
|
|
@ -1 +0,0 @@
|
|||||||
// File intentionally left blank
|
|
@ -1,259 +0,0 @@
|
|||||||
// Note, IntelliJ does not recognise the imported Java Classes, hence they are
|
|
||||||
// highlighted in Red. However, they are recognised in the gradle compilation.
|
|
||||||
|
|
||||||
|
|
||||||
// todo: look at the declaration of the script variables, can they be combined with the declaration of the Project Context
|
|
||||||
// todo: investigate adding corda-cli to the class path then executing it directly - might not work as gradle has to set up the jar file, so its not their when you start.
|
|
||||||
// Todo: write a test flow runner helper function??
|
|
||||||
// todo: rename deployCPIsHelper
|
|
||||||
// todo: add proper logging, rather than reading Stdout
|
|
||||||
// todo: add test corda running/live task
|
|
||||||
// todo: add a test to check docker is running and display error if not + halt start corda
|
|
||||||
// todo: add a clean corda task.
|
|
||||||
// todo: fix logging level and make it configurable.
|
|
||||||
|
|
||||||
|
|
||||||
import com.r3.csde.CordaLifeCycleHelper
|
|
||||||
import com.r3.csde.ProjectContext
|
|
||||||
import com.r3.csde.DeployCPIsHelper
|
|
||||||
import com.r3.csde.BuildCPIsHelper
|
|
||||||
import com.r3.csde.ProjectUtils
|
|
||||||
import com.r3.csde.CordaStatusQueries
|
|
||||||
import com.r3.csde.VNodesHelper
|
|
||||||
import com.r3.csde.NetworkConfig
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id 'java-library'
|
|
||||||
id 'groovy'
|
|
||||||
id 'java'
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
combinedWorker{
|
|
||||||
canBeConsumed = false
|
|
||||||
canBeResolved= true
|
|
||||||
}
|
|
||||||
|
|
||||||
myPostgresJDBC {
|
|
||||||
canBeConsumed = false
|
|
||||||
canBeResolved = true
|
|
||||||
}
|
|
||||||
|
|
||||||
notaryServerCPB {
|
|
||||||
canBeConsumed = false
|
|
||||||
canBeResolved = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dependencies for supporting tools
|
|
||||||
dependencies {
|
|
||||||
combinedWorker "net.corda:corda-combined-worker:$combinedWorkerVersion"
|
|
||||||
myPostgresJDBC "org.postgresql:postgresql:$postgresqlVersion"
|
|
||||||
notaryServerCPB("com.r3.corda.notary.plugin.nonvalidating:notary-plugin-non-validating-server:$cordaNotaryPluginsVersion") {
|
|
||||||
artifact {
|
|
||||||
classifier = 'package'
|
|
||||||
extension = 'cpb'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// task groupings
|
|
||||||
def cordaGroup = 'csde-corda' // corda lifecycle tasks
|
|
||||||
def cordappGroup = 'csde-cordapp' // tasks to build and deploy corDapps
|
|
||||||
def queriesGroup = 'csde-queries' // tasks which query corda status
|
|
||||||
def supportingGroup = 'supporting' // tasks which should be hidden from the csde user
|
|
||||||
|
|
||||||
|
|
||||||
def cordaBinDir = System.getenv("CSDE_CORDA_BIN") ?: System.getProperty('user.home') + "/.corda/corda5"
|
|
||||||
def cordaCliBinDir = System.getenv("CSDE_CORDA_CLI") ?:System.getProperty('user.home') + "/.corda/cli"
|
|
||||||
def cordaJDBCDir = cordaBinDir + "/jdbcDrivers"
|
|
||||||
def cordaNotaryServerDir = cordaBinDir + "/notaryserver"
|
|
||||||
def signingCertAlias="gradle-plugin-default-key"
|
|
||||||
// Get error if this is not a autotyped object
|
|
||||||
// def signingCertFName = "$rootDir/config/gradle-plugin-default-key.pem"
|
|
||||||
def signingCertFName = rootDir.toString() + "/config/gradle-plugin-default-key.pem"
|
|
||||||
def keystoreAlias = "my-signing-key"
|
|
||||||
def keystoreFName = devEnvWorkspace + "/signingkeys.pfx"
|
|
||||||
def keystoreCertFName = devEnvWorkspace + "/signingkey1.pem"
|
|
||||||
def combiWorkerPidCacheFile = devEnvWorkspace + "/CordaPID.dat"
|
|
||||||
// todo: can we rely on the build directory always being /workflow/build? aslo, is the
|
|
||||||
// workflow directory the correct place to build the cpb to. shoudl it be the main build directory.
|
|
||||||
def workflowBuildDir = rootDir.toString() + "/workflows/build"
|
|
||||||
|
|
||||||
|
|
||||||
// todo: Need to read things from cordapp plugin - the cordapp names will be changed by the user
|
|
||||||
def appCpiName = 'cpi name' // !!! this must match with the cpi name in /config/static-network-config.json
|
|
||||||
def notaryCpiName = 'CSDE Notary Server CPI'
|
|
||||||
|
|
||||||
|
|
||||||
// todo: there should be a better way to set up these project context variables.
|
|
||||||
def projectContext = new ProjectContext(project,
|
|
||||||
cordaClusterURL.toString(),
|
|
||||||
cordaRpcUser,
|
|
||||||
cordaRpcPasswd,
|
|
||||||
devEnvWorkspace,
|
|
||||||
// todo: why is this not obtained in the groovy def's abouve - its inconsistent.
|
|
||||||
new String("${System.getProperty("java.home")}/bin"),
|
|
||||||
dbContainerName,
|
|
||||||
cordaJDBCDir,
|
|
||||||
combiWorkerPidCacheFile,
|
|
||||||
signingCertAlias,
|
|
||||||
signingCertFName,
|
|
||||||
keystoreAlias,
|
|
||||||
keystoreFName,
|
|
||||||
keystoreCertFName,
|
|
||||||
appCpiName,
|
|
||||||
notaryCpiName,
|
|
||||||
devEnvWorkspace,
|
|
||||||
cordaCliBinDir,
|
|
||||||
cordaNotaryServerDir,
|
|
||||||
workflowBuildDir,
|
|
||||||
cordaNotaryPluginsVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
def networkConfig = new NetworkConfig("config/static-network-config.json")
|
|
||||||
|
|
||||||
def utils = new ProjectUtils()
|
|
||||||
|
|
||||||
// Initiate workspace folder
|
|
||||||
|
|
||||||
tasks.register('projInit') {
|
|
||||||
group = supportingGroup
|
|
||||||
doLast {
|
|
||||||
mkdir devEnvWorkspace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// CordaLifeCycle tasks
|
|
||||||
|
|
||||||
def cordaLifeCycle = new CordaLifeCycleHelper(projectContext)
|
|
||||||
|
|
||||||
tasks.register("startCorda") {
|
|
||||||
group = cordaGroup
|
|
||||||
dependsOn('getDevCordaLite', 'getPostgresJDBC')
|
|
||||||
doLast {
|
|
||||||
mkdir devEnvWorkspace
|
|
||||||
cordaLifeCycle.startCorda()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("stopCorda") {
|
|
||||||
group = cordaGroup
|
|
||||||
doLast {
|
|
||||||
cordaLifeCycle.stopCorda()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("stopAndCleanCorda") {
|
|
||||||
group = cordaGroup
|
|
||||||
dependsOn('clean')
|
|
||||||
doLast {
|
|
||||||
try {
|
|
||||||
cordaLifeCycle.stopCorda()
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
println("ignoring exception: ${ignore.toString()}")
|
|
||||||
}
|
|
||||||
delete devEnvWorkspace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("getPostgresJDBC") {
|
|
||||||
group = supportingGroup
|
|
||||||
doLast {
|
|
||||||
copy {
|
|
||||||
from configurations.myPostgresJDBC
|
|
||||||
into "$cordaJDBCDir"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("getDevCordaLite", Copy) {
|
|
||||||
group = supportingGroup
|
|
||||||
from configurations.combinedWorker
|
|
||||||
into cordaBinDir
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Corda status queries
|
|
||||||
|
|
||||||
def cordaStatusQueries = new CordaStatusQueries(projectContext)
|
|
||||||
|
|
||||||
|
|
||||||
tasks.register('listVNodes') {
|
|
||||||
group = queriesGroup
|
|
||||||
doLast {
|
|
||||||
cordaStatusQueries.listVNodes()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('listCPIs') {
|
|
||||||
group = queriesGroup
|
|
||||||
doLast {
|
|
||||||
cordaStatusQueries.listCPIs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build CPI tasks
|
|
||||||
|
|
||||||
def buildCPIsHelper = new BuildCPIsHelper(projectContext, networkConfig)
|
|
||||||
|
|
||||||
tasks.register("1-createGroupPolicy") {
|
|
||||||
group = cordappGroup
|
|
||||||
dependsOn('projInit')
|
|
||||||
doLast {
|
|
||||||
buildCPIsHelper.createGroupPolicy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("getNotaryServerCPB", Copy) {
|
|
||||||
group = supportingGroup
|
|
||||||
from configurations.notaryServerCPB
|
|
||||||
into cordaNotaryServerDir
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('2-createKeystore') {
|
|
||||||
group = cordappGroup
|
|
||||||
dependsOn('projInit')
|
|
||||||
doLast {
|
|
||||||
buildCPIsHelper.createKeyStore()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('3-buildCPIs') {
|
|
||||||
group = cordappGroup
|
|
||||||
def dependsOnTasks = subprojects.collect {it.tasks.findByName("build") }
|
|
||||||
dependsOnTasks.add('1-createGroupPolicy')
|
|
||||||
dependsOnTasks.add('2-createKeystore')
|
|
||||||
dependsOnTasks.add('getNotaryServerCPB')
|
|
||||||
dependsOn dependsOnTasks
|
|
||||||
doLast{
|
|
||||||
buildCPIsHelper.buildCPIs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// deploy CPI tasks
|
|
||||||
|
|
||||||
def deployCPIsHelper = new DeployCPIsHelper(projectContext)
|
|
||||||
|
|
||||||
tasks.register('4-deployCPIs') {
|
|
||||||
group = cordappGroup
|
|
||||||
dependsOn('3-buildCPIs')
|
|
||||||
doLast {
|
|
||||||
deployCPIsHelper.deployCPIs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup VNodes tasks
|
|
||||||
|
|
||||||
def vNodesHelper = new VNodesHelper(projectContext, networkConfig )
|
|
||||||
|
|
||||||
tasks.register('5-vNodeSetup') {
|
|
||||||
group = cordappGroup
|
|
||||||
dependsOn('4-deployCPIs')
|
|
||||||
doLast {
|
|
||||||
vNodesHelper.vNodesSetup()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,270 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
// todo: This class needs refactoring, see https://r3-cev.atlassian.net/browse/CORE-11624
|
|
||||||
public class BuildCPIsHelper {
|
|
||||||
|
|
||||||
public ProjectContext pc;
|
|
||||||
public ProjectUtils utils;
|
|
||||||
|
|
||||||
public NetworkConfig config;
|
|
||||||
public BuildCPIsHelper(ProjectContext _pc, NetworkConfig _config) {
|
|
||||||
pc = _pc;
|
|
||||||
utils = new ProjectUtils(pc);
|
|
||||||
config = _config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createGroupPolicy() throws IOException {
|
|
||||||
|
|
||||||
File groupPolicyFile = new File(String.format("%s/GroupPolicy.json", pc.devEnvWorkspace));
|
|
||||||
File devnetFile = new File(pc.project.getRootDir() + "/" + config.getConfigFilePath());
|
|
||||||
|
|
||||||
|
|
||||||
if (!groupPolicyFile.exists() || groupPolicyFile.lastModified() < devnetFile.lastModified()) {
|
|
||||||
|
|
||||||
pc.out.println("createGroupPolicy: Creating a GroupPolicy");
|
|
||||||
|
|
||||||
List<String> configX500Ids = config.getX500Names();
|
|
||||||
LinkedList<String> commandList = new LinkedList<>();
|
|
||||||
|
|
||||||
commandList.add(String.format("%s/java", pc.javaBinDir));
|
|
||||||
commandList.add(String.format("-Dpf4j.pluginsDir=%s/plugins/", pc.cordaCliBinDir));
|
|
||||||
commandList.add("-jar");
|
|
||||||
commandList.add(String.format("%s/corda-cli.jar", pc.cordaCliBinDir));
|
|
||||||
commandList.add("mgm");
|
|
||||||
commandList.add("groupPolicy");
|
|
||||||
for (String id : configX500Ids) {
|
|
||||||
commandList.add("--name");
|
|
||||||
commandList.add(id);
|
|
||||||
}
|
|
||||||
commandList.add("--endpoint-protocol=1");
|
|
||||||
commandList.add("--endpoint=http://localhost:1080");
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(commandList);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
|
|
||||||
|
|
||||||
// todo add exception catching
|
|
||||||
FileWriter fileWriter = new FileWriter(groupPolicyFile);
|
|
||||||
String line;
|
|
||||||
while (( line = reader.readLine()) != null){
|
|
||||||
fileWriter.write(line + "\n");
|
|
||||||
}
|
|
||||||
fileWriter.close();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pc.out.println("createPolicyTask: everything up to date; nothing to do.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createKeyStore() throws IOException, InterruptedException {
|
|
||||||
|
|
||||||
File keystoreFile = new File(pc.keystoreFName);
|
|
||||||
if(!keystoreFile.exists()) {
|
|
||||||
pc.out.println("createKeystore: Create a keystore");
|
|
||||||
|
|
||||||
generateKeyPair();
|
|
||||||
addDefaultSigningKey();
|
|
||||||
exportCert();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pc.out.println("createKeystore: keystore already created; nothing to do.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generateKeyPair() throws IOException, InterruptedException {
|
|
||||||
|
|
||||||
LinkedList<String> cmdArray = new LinkedList<>();
|
|
||||||
|
|
||||||
cmdArray.add(pc.javaBinDir + "/keytool");
|
|
||||||
cmdArray.add("-genkeypair");
|
|
||||||
cmdArray.add("-alias");
|
|
||||||
cmdArray.add(pc.keystoreAlias);
|
|
||||||
cmdArray.add("-keystore");
|
|
||||||
cmdArray.add(pc.keystoreFName);
|
|
||||||
cmdArray.add("-storepass");
|
|
||||||
cmdArray.add("keystore password");
|
|
||||||
cmdArray.add("-dname");
|
|
||||||
cmdArray.add("CN=CPI Example - My Signing Key, O=CorpOrgCorp, L=London, C=GB");
|
|
||||||
cmdArray.add("-keyalg");
|
|
||||||
cmdArray.add("RSA");
|
|
||||||
cmdArray.add("-storetype");
|
|
||||||
cmdArray.add("pkcs12");
|
|
||||||
cmdArray.add("-validity");
|
|
||||||
cmdArray.add("4000");
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(cmdArray);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
proc.waitFor();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDefaultSigningKey() throws IOException, InterruptedException {
|
|
||||||
|
|
||||||
LinkedList<String> cmdArray = new LinkedList<>();
|
|
||||||
|
|
||||||
cmdArray.add(pc.javaBinDir + "/keytool");
|
|
||||||
cmdArray.add("-importcert");
|
|
||||||
cmdArray.add("-keystore");
|
|
||||||
cmdArray.add(pc.keystoreFName);
|
|
||||||
cmdArray.add("-storepass");
|
|
||||||
cmdArray.add("keystore password");
|
|
||||||
cmdArray.add("-noprompt");
|
|
||||||
cmdArray.add("-alias");
|
|
||||||
cmdArray.add(pc.signingCertAlias);
|
|
||||||
cmdArray.add("-file");
|
|
||||||
cmdArray.add(pc.signingCertFName);
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(cmdArray);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
proc.waitFor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void exportCert() throws IOException, InterruptedException {
|
|
||||||
|
|
||||||
LinkedList<String> cmdArray = new LinkedList<>();
|
|
||||||
|
|
||||||
cmdArray.add(pc.javaBinDir + "/keytool");
|
|
||||||
cmdArray.add("-exportcert");
|
|
||||||
cmdArray.add("-rfc");
|
|
||||||
cmdArray.add("-alias");
|
|
||||||
cmdArray.add(pc.keystoreAlias);
|
|
||||||
cmdArray.add("-keystore");
|
|
||||||
cmdArray.add(pc.keystoreFName);
|
|
||||||
cmdArray.add("-storepass");
|
|
||||||
cmdArray.add("keystore password");
|
|
||||||
cmdArray.add("-file");
|
|
||||||
cmdArray.add(pc.keystoreCertFName);
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(cmdArray);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
proc.waitFor();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildCPIs() throws IOException, InterruptedException, CsdeException {
|
|
||||||
createCorDappCPI();
|
|
||||||
createNotaryCPI();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createCorDappCPI() throws IOException, InterruptedException, CsdeException {
|
|
||||||
|
|
||||||
String appCPIFilePath = pc.workflowBuildDir + "/" +
|
|
||||||
pc.project.getRootProject().getName() + "-" +
|
|
||||||
pc.project.getVersion() + ".cpi";
|
|
||||||
|
|
||||||
File appCPIFile = new File(appCPIFilePath);
|
|
||||||
appCPIFile.delete();
|
|
||||||
|
|
||||||
File srcDir = new File(pc.workflowBuildDir + "/libs");
|
|
||||||
File[] appCPBs = srcDir.listFiles(( x , name ) -> name.endsWith(".cpb"));
|
|
||||||
if (appCPBs == null) throw new CsdeException("Expecting exactly one CPB but no CPB found.");
|
|
||||||
if (appCPBs.length != 1) throw new CsdeException("Expecting exactly one CPB but more than one found.");
|
|
||||||
|
|
||||||
pc.out.println("appCpbs:");
|
|
||||||
pc.out.println(appCPBs[0].getAbsolutePath());
|
|
||||||
|
|
||||||
LinkedList<String> commandList = new LinkedList<>();
|
|
||||||
|
|
||||||
commandList.add(String.format("%s/java", pc.javaBinDir));
|
|
||||||
commandList.add(String.format("-Dpf4j.pluginsDir=%s/plugins/", pc.cordaCliBinDir));
|
|
||||||
commandList.add("-jar");
|
|
||||||
commandList.add(String.format("%s/corda-cli.jar", pc.cordaCliBinDir));
|
|
||||||
commandList.add("package");
|
|
||||||
commandList.add("create-cpi");
|
|
||||||
commandList.add("--cpb");
|
|
||||||
commandList.add(appCPBs[0].getAbsolutePath());
|
|
||||||
commandList.add("--group-policy");
|
|
||||||
commandList.add(pc.devEnvWorkspace + "/GroupPolicy.json");
|
|
||||||
commandList.add("--cpi-name");
|
|
||||||
commandList.add(pc.appCPIName);
|
|
||||||
commandList.add("--cpi-version");
|
|
||||||
commandList.add(pc.project.getVersion().toString());
|
|
||||||
commandList.add("--file");
|
|
||||||
commandList.add(appCPIFilePath);
|
|
||||||
commandList.add("--keystore");
|
|
||||||
commandList.add(pc.devEnvWorkspace + "/signingkeys.pfx");
|
|
||||||
commandList.add("--storepass");
|
|
||||||
commandList.add("keystore password");
|
|
||||||
commandList.add("--key");
|
|
||||||
commandList.add("my-signing-key"); // todo: should be passed as context property
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(commandList);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
proc.waitFor();
|
|
||||||
|
|
||||||
//Get CPI packaging errors
|
|
||||||
if (proc.getErrorStream().available() > 0) {
|
|
||||||
proc.getErrorStream().transferTo(pc.out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createNotaryCPI() throws CsdeException, IOException, InterruptedException {
|
|
||||||
|
|
||||||
String notaryCPIFilePath = pc.workflowBuildDir + "/" +
|
|
||||||
pc.notaryCPIName.replace(' ', '-').toLowerCase() + "-" +
|
|
||||||
pc.project.getVersion() + ".cpi";
|
|
||||||
|
|
||||||
File notaryCPIFile = new File(notaryCPIFilePath);
|
|
||||||
notaryCPIFile.delete();
|
|
||||||
|
|
||||||
File srcDir = new File(pc.cordaNotaryServiceDir);
|
|
||||||
File[] notaryCPBs = srcDir.listFiles(( x , name ) -> name.endsWith(".cpb") && name.contains(pc.cordaNotaryPluginsVersion));
|
|
||||||
if (notaryCPBs == null) throw new CsdeException("Expecting exactly one notary CPB but no CPB found.");
|
|
||||||
if (notaryCPBs.length != 1) throw new CsdeException("Expecting exactly one notary CPB but more than one found.");
|
|
||||||
|
|
||||||
pc.out.println("notaryCpbs:");
|
|
||||||
pc.out.println(notaryCPBs[0]);
|
|
||||||
|
|
||||||
LinkedList<String> commandList = new LinkedList<>();
|
|
||||||
|
|
||||||
commandList.add(String.format("%s/java", pc.javaBinDir));
|
|
||||||
commandList.add(String.format("-Dpf4j.pluginsDir=%s/plugins/", pc.cordaCliBinDir));
|
|
||||||
commandList.add("-jar");
|
|
||||||
commandList.add(String.format("%s/corda-cli.jar", pc.cordaCliBinDir));
|
|
||||||
commandList.add("package");
|
|
||||||
commandList.add("create-cpi");
|
|
||||||
commandList.add("--cpb");
|
|
||||||
commandList.add(notaryCPBs[0].getAbsolutePath());
|
|
||||||
commandList.add("--group-policy");
|
|
||||||
commandList.add(pc.devEnvWorkspace + "/GroupPolicy.json");
|
|
||||||
commandList.add("--cpi-name");
|
|
||||||
commandList.add(pc.notaryCPIName);
|
|
||||||
commandList.add("--cpi-version");
|
|
||||||
commandList.add(pc.project.getVersion().toString());
|
|
||||||
commandList.add("--file");
|
|
||||||
commandList.add(notaryCPIFilePath);
|
|
||||||
commandList.add("--keystore");
|
|
||||||
commandList.add(pc.devEnvWorkspace + "/signingkeys.pfx");
|
|
||||||
commandList.add("--storepass");
|
|
||||||
commandList.add("keystore password");
|
|
||||||
commandList.add("--key");
|
|
||||||
commandList.add("my-signing-key");
|
|
||||||
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(commandList);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
Process proc = pb.start();
|
|
||||||
proc.waitFor();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: this might be needed for improved logging
|
|
||||||
private void printCmdArray(LinkedList<String> cmdArray) {
|
|
||||||
for (int i = 0; i < cmdArray.size(); i++) {
|
|
||||||
pc.out.print(cmdArray.get(i) + " ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import kong.unirest.Unirest;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manages Bringing corda up, testing for liveness and taking corda down
|
|
||||||
*/
|
|
||||||
// todo: This class needs refactoring, see https://r3-cev.atlassian.net/browse/CORE-11624
|
|
||||||
public class CordaLifeCycleHelper {
|
|
||||||
|
|
||||||
ProjectContext pc;
|
|
||||||
ProjectUtils utils;
|
|
||||||
|
|
||||||
public CordaLifeCycleHelper(ProjectContext _pc) {
|
|
||||||
pc = _pc;
|
|
||||||
utils = new ProjectUtils(pc);
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startCorda() throws IOException, CsdeException {
|
|
||||||
File cordaPIDFile = new File(pc.cordaPidCache);
|
|
||||||
if (cordaPIDFile.exists()) {
|
|
||||||
throw new CsdeException("Cannot start the Combined worker. Cached process ID file " + cordaPIDFile + " existing. Was the combined worker already started?");
|
|
||||||
}
|
|
||||||
PrintStream pidStore = new PrintStream(new FileOutputStream(cordaPIDFile));
|
|
||||||
File combinedWorkerJar = pc.project.getConfigurations().getByName("combinedWorker").getSingleFile();
|
|
||||||
|
|
||||||
// Manual version of the command to start postgres (for reference):
|
|
||||||
// docker run -d --rm -p5432:5432 --name CSDEpostgresql -e POSTGRES_DB=cordacluster -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=password postgres:latest
|
|
||||||
|
|
||||||
new ProcessBuilder(
|
|
||||||
"docker",
|
|
||||||
"run", "-d", "--rm",
|
|
||||||
"-p", "5432:5432",
|
|
||||||
"--name", pc.dbContainerName,
|
|
||||||
"-e", "POSTGRES_DB=cordacluster",
|
|
||||||
"-e", "POSTGRES_USER=postgres",
|
|
||||||
"-e", "POSTGRES_PASSWORD=password",
|
|
||||||
"postgres:latest").start();
|
|
||||||
|
|
||||||
// todo: we should poll for readiness not wait 10 seconds, see https://r3-cev.atlassian.net/browse/CORE-11626
|
|
||||||
utils.rpcWait(10000);
|
|
||||||
|
|
||||||
ProcessBuilder procBuild = new ProcessBuilder(pc.javaBinDir + "/java",
|
|
||||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005",
|
|
||||||
"-DsecurityMangerEnabled=false",
|
|
||||||
"-Dlog4j.configurationFile=" + pc.project.getRootDir() + "/config/log4j2.xml",
|
|
||||||
"-Dco.paralleluniverse.fibers.verifyInstrumentation=true",
|
|
||||||
"-jar",
|
|
||||||
combinedWorkerJar.toString(),
|
|
||||||
"--instance-id=0",
|
|
||||||
"-mbus.busType=DATABASE",
|
|
||||||
"-spassphrase=password",
|
|
||||||
"-ssalt=salt",
|
|
||||||
"-ddatabase.user=user",
|
|
||||||
"-ddatabase.pass=password",
|
|
||||||
"-ddatabase.jdbc.url=jdbc:postgresql://localhost:5432/cordacluster",
|
|
||||||
"-ddatabase.jdbc.directory="+pc.JDBCDir);
|
|
||||||
|
|
||||||
procBuild.redirectErrorStream(true);
|
|
||||||
Process proc = procBuild.start();
|
|
||||||
pidStore.print(proc.pid());
|
|
||||||
pc.out.println("Corda Process-id="+proc.pid());
|
|
||||||
proc.getInputStream().transferTo(pc.out);
|
|
||||||
|
|
||||||
// todo: we should poll for readiness before completing the startCorda task, see https://r3-cev.atlassian.net/browse/CORE-11625
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void stopCorda() throws IOException, CsdeException {
|
|
||||||
File cordaPIDFile = new File(pc.cordaPidCache);
|
|
||||||
if(cordaPIDFile.exists()) {
|
|
||||||
Scanner sc = new Scanner(cordaPIDFile);
|
|
||||||
long pid = sc.nextLong();
|
|
||||||
pc.out.println("pid to kill=" + pid);
|
|
||||||
|
|
||||||
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
|
|
||||||
new ProcessBuilder("Powershell", "-Command", "Stop-Process", "-Id", Long.toString(pid), "-PassThru").start();
|
|
||||||
} else {
|
|
||||||
new ProcessBuilder("kill", "-9", Long.toString(pid)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
Process proc = new ProcessBuilder("docker", "stop", pc.dbContainerName).start();
|
|
||||||
|
|
||||||
cordaPIDFile.delete();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new CsdeException("Cannot stop the Combined worker. Cached process ID file " + pc.cordaPidCache + " missing. Was the combined worker not started?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import kong.unirest.HttpResponse;
|
|
||||||
import kong.unirest.JsonNode;
|
|
||||||
import kong.unirest.Unirest;
|
|
||||||
import kong.unirest.json.JSONArray;
|
|
||||||
import kong.unirest.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
// todo: This class needs refactoring, see https://r3-cev.atlassian.net/browse/CORE-11624
|
|
||||||
public class CordaStatusQueries {
|
|
||||||
|
|
||||||
ProjectContext pc;
|
|
||||||
|
|
||||||
public CordaStatusQueries(ProjectContext _pc) {
|
|
||||||
pc = _pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpResponse<JsonNode> getCpiInfo() {
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
return Unirest.get(pc.baseURL + "/api/v1/cpi/")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpResponse<JsonNode> getVNodeInfo() {
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
return Unirest.get(pc.baseURL + "/api/v1/virtualnode/")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
// cpiName, cpiVersion
|
|
||||||
public void listCPIs() {
|
|
||||||
HttpResponse<JsonNode> cpiResponse = getCpiInfo();
|
|
||||||
|
|
||||||
JSONArray cpisJson = (JSONArray) cpiResponse.getBody().getObject().get("cpis");
|
|
||||||
|
|
||||||
List<List<String>> lines = new LinkedList<>();
|
|
||||||
for (Object o : cpisJson) {
|
|
||||||
if (o instanceof JSONObject) {
|
|
||||||
JSONObject idObj = ((JSONObject) o).getJSONObject("id");
|
|
||||||
String cpiName = idObj.get("cpiName").toString();
|
|
||||||
String cpiVersion = idObj.get("cpiVersion").toString();
|
|
||||||
|
|
||||||
lines.add(Arrays.asList(cpiName, cpiVersion));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<String> title = Arrays.asList("CPI Name", "CPI Version");
|
|
||||||
List<Integer> titleSizes = Arrays.asList(40, 20);
|
|
||||||
printTable(titleSizes, title, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void listVNodesVerbose() {
|
|
||||||
HttpResponse<JsonNode> vnodeResponse = getVNodeInfo();
|
|
||||||
pc.out.println("VNodes:\n" + vnodeResponse.getBody().toPrettyString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// x500Name, shortHash, cpiName
|
|
||||||
public void listVNodes() {
|
|
||||||
HttpResponse<JsonNode> vnodeResponse = getVNodeInfo();
|
|
||||||
|
|
||||||
JSONArray virtualNodesJson = (JSONArray) vnodeResponse.getBody().getObject().get("virtualNodes");
|
|
||||||
|
|
||||||
List<List<String>> lines = new LinkedList<>();
|
|
||||||
for (Object o : virtualNodesJson) {
|
|
||||||
if (o instanceof JSONObject) {
|
|
||||||
JSONObject idObj = ((JSONObject) o).getJSONObject("holdingIdentity");
|
|
||||||
String x500Name = idObj.get("x500Name").toString();
|
|
||||||
String shortHash = idObj.get("shortHash").toString();
|
|
||||||
|
|
||||||
JSONObject cpiObj = ((JSONObject) o).getJSONObject("cpiIdentifier");
|
|
||||||
String cpiName = cpiObj.get("cpiName").toString();
|
|
||||||
|
|
||||||
lines.add(Arrays.asList(x500Name, shortHash, cpiName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<String> title = Arrays.asList("X500 Name", "Holding identity short hash", "CPI Name");
|
|
||||||
List<Integer> titleSizes = Arrays.asList(60, 30, 40);
|
|
||||||
printTable(titleSizes, title, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printTable(List<Integer> titleSizes, List<String> title, List<List<String>> lines) {
|
|
||||||
int width = titleSizes.stream().reduce(0, Integer::sum);
|
|
||||||
String separator = "-".repeat(width + 1);
|
|
||||||
pc.out.println(separator);
|
|
||||||
pc.out.println(formatLine(titleSizes, title));
|
|
||||||
pc.out.println(separator);
|
|
||||||
for (List<String> line : lines) {
|
|
||||||
pc.out.println(formatLine(titleSizes, line));
|
|
||||||
}
|
|
||||||
pc.out.println(separator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String formatLine(List<Integer> titleSizes, List<String> line) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
int delta = 0;
|
|
||||||
for (int i = 0; i < titleSizes.size(); i++) {
|
|
||||||
String s = line.get(i);
|
|
||||||
sb.append("| ").append(s);
|
|
||||||
delta += titleSizes.get(i) - (2 + s.length());
|
|
||||||
|
|
||||||
if (delta > 0) {
|
|
||||||
sb.append(" ".repeat(delta));
|
|
||||||
delta = 0;
|
|
||||||
} else {
|
|
||||||
sb.append(" ");
|
|
||||||
delta -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sb.append("|");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
public class CsdeException extends Exception {
|
|
||||||
public CsdeException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
public CsdeException(String message){
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import kong.unirest.JsonNode;
|
|
||||||
import kong.unirest.Unirest;
|
|
||||||
import kong.unirest.json.JSONArray;
|
|
||||||
import kong.unirest.json.JSONObject;
|
|
||||||
import kong.unirest.HttpResponse;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
|
|
||||||
import static java.net.HttpURLConnection.HTTP_OK;
|
|
||||||
|
|
||||||
// todo: This class needs refactoring, see https://r3-cev.atlassian.net/browse/CORE-11624
|
|
||||||
public class DeployCPIsHelper {
|
|
||||||
|
|
||||||
public DeployCPIsHelper() {
|
|
||||||
}
|
|
||||||
ProjectContext pc;
|
|
||||||
CordaStatusQueries queries;
|
|
||||||
ProjectUtils utils;
|
|
||||||
|
|
||||||
public DeployCPIsHelper(ProjectContext _pc) {
|
|
||||||
pc = _pc;
|
|
||||||
queries = new CordaStatusQueries(pc);
|
|
||||||
utils = new ProjectUtils(pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deployCPIs() throws FileNotFoundException, CsdeException{
|
|
||||||
|
|
||||||
uploadCertificate(pc.signingCertAlias, pc.signingCertFName);
|
|
||||||
uploadCertificate(pc.keystoreAlias, pc.keystoreCertFName);
|
|
||||||
|
|
||||||
// todo: make consistent with other string building code - remove String.format
|
|
||||||
String appCPILocation = String.format("%s/%s-%s.cpi",
|
|
||||||
pc.workflowBuildDir,
|
|
||||||
pc.project.getName(),
|
|
||||||
pc.project.getVersion());
|
|
||||||
deployCPI(appCPILocation, pc.appCPIName,pc.project.getVersion().toString());
|
|
||||||
|
|
||||||
String notaryCPILocation = String.format("%s/%s-%s.cpi",
|
|
||||||
pc.workflowBuildDir,
|
|
||||||
pc.notaryCPIName.replace(' ','-').toLowerCase(),
|
|
||||||
pc.project.getVersion());
|
|
||||||
deployCPI(notaryCPILocation,
|
|
||||||
pc.notaryCPIName,
|
|
||||||
pc.project.getVersion().toString(),
|
|
||||||
"-NotaryServer" );
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void uploadCertificate(String certAlias, String certFName) {
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
HttpResponse<JsonNode> uploadResponse = Unirest.put(pc.baseURL + "/api/v1/certificates/cluster/code-signer")
|
|
||||||
.field("alias", certAlias)
|
|
||||||
.field("certificate", new File(certFName))
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
pc.out.println("Certificate/key upload, alias "+certAlias+" certificate/key file "+certFName);
|
|
||||||
pc.out.println(uploadResponse.getBody().toPrettyString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void forceuploadCPI(String cpiFName) throws FileNotFoundException, CsdeException {
|
|
||||||
forceuploadCPI(cpiFName, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void forceuploadCPI(String cpiFName, String uploadStatusQualifier) throws FileNotFoundException, CsdeException {
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
HttpResponse<JsonNode> jsonResponse = Unirest.post(pc.baseURL + "/api/v1/maintenance/virtualnode/forcecpiupload/")
|
|
||||||
.field("upload", new File(cpiFName))
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if(jsonResponse.getStatus() == HTTP_OK) {
|
|
||||||
String id = (String) jsonResponse.getBody().getObject().get("id");
|
|
||||||
pc.out.println("get id:\n" +id);
|
|
||||||
HttpResponse<JsonNode> statusResponse = uploadStatus(id);
|
|
||||||
|
|
||||||
if (statusResponse.getStatus() == HTTP_OK) {
|
|
||||||
PrintStream cpiUploadStatus = new PrintStream(new FileOutputStream(
|
|
||||||
pc.CPIUploadStatusFName.replace(".json", uploadStatusQualifier + ".json" )));
|
|
||||||
cpiUploadStatus.print(statusResponse.getBody());
|
|
||||||
pc.out.println("Caching CPI file upload status:\n" + statusResponse.getBody());
|
|
||||||
} else {
|
|
||||||
utils.reportError(statusResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
utils.reportError(jsonResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean uploadStatusRetry(HttpResponse<JsonNode> response) {
|
|
||||||
int status = response.getStatus();
|
|
||||||
JsonNode body = response.getBody();
|
|
||||||
// Do not retry on success // todo: need to think through the possible outcomes here - what if the bodyTitle is null, it won't retry
|
|
||||||
if(status == HTTP_OK) {
|
|
||||||
// Keep retrying until we get "OK" may move through "Validating upload", "Persisting CPI"
|
|
||||||
return !(body.getObject().get("status").equals("OK"));
|
|
||||||
}
|
|
||||||
else if (status == HTTP_BAD_REQUEST){
|
|
||||||
String bodyTitle = response.getBody().getObject().getString("title");
|
|
||||||
return bodyTitle != null && bodyTitle.matches("No such requestId=[-0-9a-f]+");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpResponse<JsonNode> uploadStatus(String requestId) {
|
|
||||||
HttpResponse<JsonNode> statusResponse = null;
|
|
||||||
do {
|
|
||||||
utils.rpcWait(1000);
|
|
||||||
statusResponse = Unirest
|
|
||||||
.get(pc.baseURL + "/api/v1/cpi/status/" + requestId + "/")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
pc.out.println("Upload status="+statusResponse.getStatus()+", status query response:\n"+statusResponse.getBody().toPrettyString());
|
|
||||||
}
|
|
||||||
while(uploadStatusRetry(statusResponse));
|
|
||||||
|
|
||||||
return statusResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deployCPI(String cpiFName, String cpiName, String cpiVersion) throws FileNotFoundException, CsdeException {
|
|
||||||
deployCPI(cpiFName, cpiName, cpiVersion, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deployCPI(String cpiFName,
|
|
||||||
String cpiName,
|
|
||||||
String cpiVersion,
|
|
||||||
String uploadStatusQualifier) throws FileNotFoundException, CsdeException {
|
|
||||||
// todo: where is the primary instance declared?
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
|
|
||||||
HttpResponse<JsonNode> cpiResponse = queries.getCpiInfo();
|
|
||||||
JSONArray jArray = (JSONArray) cpiResponse.getBody().getObject().get("cpis");
|
|
||||||
|
|
||||||
int matches = 0;
|
|
||||||
for(Object o: jArray.toList() ) {
|
|
||||||
if(o instanceof JSONObject) {
|
|
||||||
JSONObject idObj = ((JSONObject) o).getJSONObject("id");
|
|
||||||
if((idObj.get("cpiName").toString().equals(cpiName)
|
|
||||||
&& idObj.get("cpiVersion").toString().equals(cpiVersion))) {
|
|
||||||
matches++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pc.out.println("Matching CPIS="+matches);
|
|
||||||
|
|
||||||
if(matches == 0) {
|
|
||||||
HttpResponse<JsonNode> uploadResponse = Unirest.post(pc.baseURL + "/api/v1/cpi/")
|
|
||||||
.field("upload", new File(cpiFName))
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
JsonNode body = uploadResponse.getBody();
|
|
||||||
|
|
||||||
int status = uploadResponse.getStatus();
|
|
||||||
|
|
||||||
pc.out.println("Upload Status:" + status);
|
|
||||||
pc.out.println("Pretty print the body\n" + body.toPrettyString());
|
|
||||||
|
|
||||||
// We expect the id field to be a string.
|
|
||||||
if (status == HTTP_OK) {
|
|
||||||
String id = (String) body.getObject().get("id");
|
|
||||||
pc.out.println("get id:\n" + id);
|
|
||||||
|
|
||||||
HttpResponse<JsonNode> statusResponse = uploadStatus(id);
|
|
||||||
if (statusResponse.getStatus() == HTTP_OK) {
|
|
||||||
PrintStream cpiUploadStatus = new PrintStream(new FileOutputStream(
|
|
||||||
pc.CPIUploadStatusFName.replace(".json", uploadStatusQualifier + ".json" )));
|
|
||||||
cpiUploadStatus.print(statusResponse.getBody());
|
|
||||||
pc.out.println("Caching CPI file upload status:\n" + statusResponse.getBody());
|
|
||||||
} else {
|
|
||||||
utils.reportError(statusResponse);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
utils.reportError(uploadResponse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pc.out.println("CPI already uploaded doing a 'force' upload.");
|
|
||||||
forceuploadCPI(cpiFName, uploadStatusQualifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class reads the network config from the json file and makes it available as a list of VNodes.
|
|
||||||
*/
|
|
||||||
public class NetworkConfig {
|
|
||||||
|
|
||||||
private List<VNode> vNodes;
|
|
||||||
private String configFilePath;
|
|
||||||
|
|
||||||
public NetworkConfig(String _configFilePath) throws CsdeException {
|
|
||||||
configFilePath = _configFilePath;
|
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
try {
|
|
||||||
FileInputStream in = new FileInputStream(configFilePath);
|
|
||||||
vNodes = mapper.readValue(in, new TypeReference<List<VNode>>() {
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new CsdeException("Failed to read static network configuration file, with exception: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getConfigFilePath() { return configFilePath; }
|
|
||||||
|
|
||||||
List<VNode> getVNodes() { return vNodes; }
|
|
||||||
|
|
||||||
List<String> getX500Names() {
|
|
||||||
return vNodes.stream().map(vn -> vn.getX500Name()).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class ProjectContext {
|
|
||||||
Project project;
|
|
||||||
String baseURL = "https://localhost:8888";
|
|
||||||
String rpcUser = "admin";
|
|
||||||
String rpcPasswd = "admin";
|
|
||||||
String workspaceDir = "workspace";
|
|
||||||
int retryWaitMs = 1000;
|
|
||||||
PrintStream out = System.out;
|
|
||||||
String CPIUploadStatusBaseName = "CPIFileStatus.json";
|
|
||||||
String NotaryCPIUploadBaseName = "CPIFileStatus-NotaryServer.json";
|
|
||||||
String CPIUploadStatusFName;
|
|
||||||
String NotaryCPIUploadStatusFName;
|
|
||||||
String javaBinDir;
|
|
||||||
String cordaPidCache = "CordaPIDCache.dat";
|
|
||||||
String dbContainerName;
|
|
||||||
String JDBCDir;
|
|
||||||
String combinedWorkerBinRe;
|
|
||||||
Map<String, String> notaryRepresentatives = null;
|
|
||||||
String signingCertAlias;
|
|
||||||
String signingCertFName;
|
|
||||||
String keystoreAlias;
|
|
||||||
String keystoreFName;
|
|
||||||
String keystoreCertFName;
|
|
||||||
String appCPIName;
|
|
||||||
String notaryCPIName;
|
|
||||||
String devEnvWorkspace;
|
|
||||||
String cordaCliBinDir;
|
|
||||||
String cordaNotaryServiceDir;
|
|
||||||
String workflowBuildDir;
|
|
||||||
String cordaNotaryPluginsVersion;
|
|
||||||
|
|
||||||
public ProjectContext (Project inProject,
|
|
||||||
String inBaseUrl,
|
|
||||||
String inRpcUser,
|
|
||||||
String inRpcPasswd,
|
|
||||||
String inWorkspaceDir,
|
|
||||||
String inJavaBinDir,
|
|
||||||
String inDbContainerName,
|
|
||||||
String inJDBCDir,
|
|
||||||
String inCordaPidCache,
|
|
||||||
String inSigningCertAlias,
|
|
||||||
String inSigningCertFName,
|
|
||||||
String inKeystoreAlias,
|
|
||||||
String inKeystoreFName,
|
|
||||||
String inKeystoreCertFName,
|
|
||||||
String inAppCPIName,
|
|
||||||
String inNotaryCPIName,
|
|
||||||
String inDevEnvWorkspace,
|
|
||||||
String inCordaCLiBinDir,
|
|
||||||
String inCordaNotaryServiceDir,
|
|
||||||
String inWorkflowBuildDir,
|
|
||||||
String inCordaNotaryPluginsVersion
|
|
||||||
) {
|
|
||||||
project = inProject;
|
|
||||||
baseURL = inBaseUrl;
|
|
||||||
rpcUser = inRpcUser;
|
|
||||||
rpcPasswd = inRpcPasswd;
|
|
||||||
workspaceDir = inWorkspaceDir;
|
|
||||||
javaBinDir = inJavaBinDir;
|
|
||||||
cordaPidCache = inCordaPidCache;
|
|
||||||
dbContainerName = inDbContainerName;
|
|
||||||
JDBCDir = inJDBCDir;
|
|
||||||
CPIUploadStatusFName = workspaceDir + "/" + CPIUploadStatusBaseName;
|
|
||||||
NotaryCPIUploadStatusFName = workspaceDir + "/" + NotaryCPIUploadBaseName;
|
|
||||||
signingCertAlias = inSigningCertAlias;
|
|
||||||
signingCertFName = inSigningCertFName;
|
|
||||||
keystoreAlias = inKeystoreAlias;
|
|
||||||
keystoreFName = inKeystoreFName;
|
|
||||||
keystoreCertFName = inKeystoreCertFName;
|
|
||||||
appCPIName = inAppCPIName;
|
|
||||||
notaryCPIName = inNotaryCPIName;
|
|
||||||
devEnvWorkspace = inDevEnvWorkspace;
|
|
||||||
cordaCliBinDir = inCordaCLiBinDir;
|
|
||||||
cordaNotaryServiceDir = inCordaNotaryServiceDir;
|
|
||||||
workflowBuildDir = inWorkflowBuildDir;
|
|
||||||
cordaNotaryPluginsVersion = inCordaNotaryPluginsVersion;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import kong.unirest.HttpResponse;
|
|
||||||
import kong.unirest.JsonNode;
|
|
||||||
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
// todo: This class needs refactoring, see https://r3-cev.atlassian.net/browse/CORE-11624
|
|
||||||
public class ProjectUtils {
|
|
||||||
|
|
||||||
ProjectContext pc;
|
|
||||||
|
|
||||||
ProjectUtils(ProjectContext _pc) {
|
|
||||||
pc = _pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpcWait(int millis) {
|
|
||||||
try {
|
|
||||||
sleep(millis);
|
|
||||||
}
|
|
||||||
catch(InterruptedException e) {
|
|
||||||
throw new UnsupportedOperationException("Interrupts not supported.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reportError(HttpResponse<JsonNode> response) throws CsdeException {
|
|
||||||
|
|
||||||
pc.out.println("*** *** ***");
|
|
||||||
pc.out.println("Unexpected response from Corda");
|
|
||||||
pc.out.println("Status="+ response.getStatus());
|
|
||||||
pc.out.println("*** Headers ***\n"+ response.getHeaders());
|
|
||||||
pc.out.println("*** Body ***\n"+ response.getBody());
|
|
||||||
pc.out.println("*** *** ***");
|
|
||||||
throw new CsdeException("Error: unexpected response from Corda.");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is a representation of a Vnode used to express the vNodes required on the network.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class VNode {
|
|
||||||
private String x500Name;
|
|
||||||
private String cpi;
|
|
||||||
|
|
||||||
private String serviceX500Name;
|
|
||||||
|
|
||||||
public VNode() { }
|
|
||||||
|
|
||||||
public String getX500Name(){ return x500Name; }
|
|
||||||
public void setX500Name(String _x500Name) { x500Name = _x500Name; }
|
|
||||||
|
|
||||||
public String getCpi() { return cpi; }
|
|
||||||
public void setCpi(String _cpi) { cpi = _cpi; }
|
|
||||||
|
|
||||||
public String getServiceX500Name() { return serviceX500Name; }
|
|
||||||
public void setServiceX500Name(String _name) { serviceX500Name = _name; }
|
|
||||||
|
|
||||||
}
|
|
@ -1,288 +0,0 @@
|
|||||||
package com.r3.csde;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.r3.csde.dtos.*;
|
|
||||||
import kong.unirest.HttpResponse;
|
|
||||||
import kong.unirest.JsonNode;
|
|
||||||
import kong.unirest.Unirest;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import static java.net.HttpURLConnection.HTTP_OK;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The VNodesHelper class is used to create and register the Vnodes specified in the static-network-config.json file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class VNodesHelper {
|
|
||||||
private ProjectContext pc;
|
|
||||||
private ProjectUtils utils;
|
|
||||||
private NetworkConfig config;
|
|
||||||
private ObjectMapper mapper;
|
|
||||||
|
|
||||||
public VNodesHelper(ProjectContext _pc, NetworkConfig _config) {
|
|
||||||
pc = _pc;
|
|
||||||
utils = new ProjectUtils(pc);
|
|
||||||
config = _config;
|
|
||||||
Unirest.config().verifySsl(false);
|
|
||||||
mapper = new ObjectMapper();
|
|
||||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry point for setting up vnodes, called from the 5-vNodeSetup task in csde.gradle
|
|
||||||
*/
|
|
||||||
public void vNodesSetup() throws CsdeException {
|
|
||||||
List<VNode> requiredNodes = config.getVNodes();
|
|
||||||
createVNodes(requiredNodes);
|
|
||||||
registerVNodes(requiredNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates vnodes specified in the config if they don't already exist.
|
|
||||||
* @param requiredNodes represents the list of VNodes as specified in the network Config json file (static-network-config.json)
|
|
||||||
*/
|
|
||||||
private void createVNodes(List<VNode> requiredNodes) throws CsdeException {
|
|
||||||
|
|
||||||
// Get existing Nodes.
|
|
||||||
List<VirtualNodeInfoDTO> existingVNodes = getExistingNodes();
|
|
||||||
|
|
||||||
// Check if each required vnode already exist, if not create it.
|
|
||||||
for (VNode vn : requiredNodes) {
|
|
||||||
// Match on x500 and cpi name
|
|
||||||
List<VirtualNodeInfoDTO> matches = existingVNodes
|
|
||||||
.stream()
|
|
||||||
.filter(existing ->
|
|
||||||
existing.getHoldingIdentity().getX500Name().equals( vn.getX500Name()) &&
|
|
||||||
existing.getCpiIdentifier().getCpiName().equals(vn.getCpi()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (matches.size() == 0) {
|
|
||||||
createVNode(vn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a list of the virtual nodes which have already been created.
|
|
||||||
* @return a list of the virtual nodes which have already been created.
|
|
||||||
*/
|
|
||||||
private List<VirtualNodeInfoDTO> getExistingNodes () throws CsdeException {
|
|
||||||
|
|
||||||
HttpResponse<JsonNode> response = Unirest.get(pc.baseURL + "/api/v1/virtualnode")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if (response.getStatus() != HTTP_OK) {
|
|
||||||
throw new CsdeException("Failed to get Existing vNodes, response status: "+ response.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return mapper.readValue(response.getBody().toString(), VirtualNodesDTO.class).getVirtualNodes();
|
|
||||||
} catch (Exception e){
|
|
||||||
throw new CsdeException("Failed to get Existing vNodes with exception: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a vnode on the Corda cluster from the VNode info.
|
|
||||||
* @param vNode represents a virtual node using VNode Class.
|
|
||||||
*/
|
|
||||||
private void createVNode(VNode vNode) throws CsdeException {
|
|
||||||
|
|
||||||
pc.out.println("Creating virtual node for "+ vNode.getX500Name());
|
|
||||||
|
|
||||||
// Reads the current CPIFileChecksum value and checks it has been uploaded.
|
|
||||||
String cpiCheckSum = getCpiCheckSum(vNode);
|
|
||||||
if (!checkCpiUploaded(cpiCheckSum)) throw new CsdeException("Cpi " + cpiCheckSum + " not uploaded.");
|
|
||||||
|
|
||||||
// Creates the vnode on Cluster
|
|
||||||
HttpResponse<JsonNode> response = Unirest.post(pc.baseURL + "/api/v1/virtualnode")
|
|
||||||
.body("{ \"request\" : { \"cpiFileChecksum\": \"" + cpiCheckSum + "\", \"x500Name\": \"" + vNode.getX500Name() + "\" } }")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if (response.getStatus() != HTTP_OK) {
|
|
||||||
throw new CsdeException("Creation of virtual node failed with response status: " + response.getStatus());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the latest CPI checksums from file.
|
|
||||||
* @param vNode represents a virtual node using VNode Class.
|
|
||||||
*/
|
|
||||||
private String getCpiCheckSum(VNode vNode) throws CsdeException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
String file = (vNode.getServiceX500Name() == null) ? pc.CPIUploadStatusFName : pc.NotaryCPIUploadStatusFName;
|
|
||||||
FileInputStream in = new FileInputStream(file);
|
|
||||||
CPIFileStatusDTO statusDTO = mapper.readValue(in, CPIFileStatusDTO.class);
|
|
||||||
return statusDTO.getCpiFileChecksum().toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new CsdeException("Failed to read CPI checksum from file, with error: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkCpiUploaded(String cpiCheckSum) throws CsdeException {
|
|
||||||
|
|
||||||
HttpResponse<JsonNode> response = Unirest.get(pc.baseURL + "/api/v1/cpi")
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if (response.getStatus() != HTTP_OK) {
|
|
||||||
throw new CsdeException("Failed to check cpis, response status: " + response.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
GetCPIsResponseDTO cpisResponse = mapper.readValue(
|
|
||||||
response.getBody().toString(), GetCPIsResponseDTO.class);
|
|
||||||
|
|
||||||
for (CpiMetadataDTO cpi: cpisResponse.getCpis()) {
|
|
||||||
if (Objects.equals(cpi.getCpiFileChecksum(), cpiCheckSum)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Returns false if no cpis were returned or the cpiCheckSum didnt' match ay results.
|
|
||||||
return false;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new CsdeException("Failed to check cpis with exception: " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the required virtual nodes have been registered and if not registers them.
|
|
||||||
* @param requiredNodes represents the list of VNodes as specified in the network Config json file (static-network-config.json)
|
|
||||||
*/
|
|
||||||
private void registerVNodes(List<VNode> requiredNodes) throws CsdeException {
|
|
||||||
|
|
||||||
// There appears to be a delay between the successful post /virtualnodes synchronous call and the
|
|
||||||
// vnodes being returned in the GET /virtualnodes call. Putting a thread wait here as a quick fix
|
|
||||||
// as this will move to async mechanism post beta2.
|
|
||||||
utils.rpcWait(2000);
|
|
||||||
List<VirtualNodeInfoDTO> existingVNodes = getExistingNodes();
|
|
||||||
|
|
||||||
for (VNode vn: requiredNodes) {
|
|
||||||
// Match on x500 and cpi name
|
|
||||||
List<VirtualNodeInfoDTO> matches = existingVNodes
|
|
||||||
.stream()
|
|
||||||
.filter(existing ->
|
|
||||||
existing.getHoldingIdentity().getX500Name().equals( vn.getX500Name()) &&
|
|
||||||
existing.getCpiIdentifier().getCpiName().equals(vn.getCpi()))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
if (matches.size() == 0) {
|
|
||||||
throw new CsdeException("Registration failed because virtual node for '" + vn.getX500Name() + "' not found.");
|
|
||||||
} else if (matches.size() >1 ) {
|
|
||||||
throw new CsdeException(("Registration failed because more than virtual node for '" + vn.getX500Name() + "'"));
|
|
||||||
}
|
|
||||||
|
|
||||||
String shortHash = matches.get(0).getHoldingIdentity().getShortHash();
|
|
||||||
|
|
||||||
if (!checkVNodeIsRegistered(shortHash)) {
|
|
||||||
registerVnode(vn, shortHash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a virtual node.
|
|
||||||
* @param vnode represents the vnode to be registered.
|
|
||||||
* @param shortHash the shortHash of the virtual node to register.
|
|
||||||
*/
|
|
||||||
private void registerVnode(VNode vnode, String shortHash) throws CsdeException {
|
|
||||||
|
|
||||||
pc.out.println("Registering vNode: " + vnode.getX500Name() + " with shortHash: " + shortHash);
|
|
||||||
|
|
||||||
// Configure the registration body (notary vs non notary)
|
|
||||||
String registrationBody;
|
|
||||||
if (vnode.getServiceX500Name() == null) {
|
|
||||||
registrationBody =
|
|
||||||
"{ \"action\" : \"requestJoin\"," +
|
|
||||||
" \"context\" : {" +
|
|
||||||
" \"corda.key.scheme\" : \"CORDA.ECDSA.SECP256R1\" } }";
|
|
||||||
} else {
|
|
||||||
registrationBody =
|
|
||||||
"{ \"action\" : \"requestJoin\"," +
|
|
||||||
" \"context\" : {" +
|
|
||||||
" \"corda.key.scheme\" : \"CORDA.ECDSA.SECP256R1\", " +
|
|
||||||
" \"corda.roles.0\" : \"notary\", " +
|
|
||||||
" \"corda.notary.service.name\" : \"" + vnode.getServiceX500Name() + "\", " +
|
|
||||||
" \"corda.notary.service.plugin\" : \"net.corda.notary.NonValidatingNotary\" } }";
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpResponse<JsonNode> response = Unirest.post(pc.baseURL + "/api/v1/membership/" + shortHash)
|
|
||||||
.body(registrationBody)
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if (response.getStatus() == HTTP_OK) {
|
|
||||||
pc.out.println("Membership requested for node " + shortHash);
|
|
||||||
} else {
|
|
||||||
throw new CsdeException("Failed to register virtual node " + shortHash + ", response status: " + response.getStatus() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait until Vnode registered
|
|
||||||
pollForRegistration(shortHash, 30000, 1000);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a virtual node with given shortHash has been registered
|
|
||||||
* @param shortHash shortHash of the node which is being checked.
|
|
||||||
* @return returns true if the vnode is registered
|
|
||||||
*/
|
|
||||||
private boolean checkVNodeIsRegistered(String shortHash) throws CsdeException {
|
|
||||||
|
|
||||||
// Queries registration status for vnode.
|
|
||||||
HttpResponse<JsonNode> response = Unirest.get(pc.baseURL + "/api/v1/membership/" + shortHash)
|
|
||||||
.basicAuth(pc.rpcUser, pc.rpcPasswd)
|
|
||||||
.asJson();
|
|
||||||
|
|
||||||
if (response.getStatus() != HTTP_OK)
|
|
||||||
throw new CsdeException("Failed to check registration status for virtual node '" + shortHash +
|
|
||||||
"' response status: " + response.getStatus());
|
|
||||||
|
|
||||||
try {
|
|
||||||
// If the response body is not empty check all previous requests for an "APPROVED"
|
|
||||||
if (!response.getBody().getArray().isEmpty()) {
|
|
||||||
List<RegistrationRequestProgressDTO> requests = mapper.readValue(
|
|
||||||
response.getBody().toString(), new TypeReference<>() {
|
|
||||||
});
|
|
||||||
for (RegistrationRequestProgressDTO request : requests) {
|
|
||||||
if (Objects.equals(request.getRegistrationStatus(), "APPROVED")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Returns false if array was empty or "APPROVED" wasn't found
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new CsdeException("Failed to check registration status for " + shortHash +
|
|
||||||
" with exception " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polls for registration of a vnode
|
|
||||||
* @param shortHash short hash of the node which is being poled for
|
|
||||||
* @param duration the number of milliseconds before the pollign times out
|
|
||||||
* @param cooldown the number of milliseconds in between poll attempts.
|
|
||||||
*/
|
|
||||||
private void pollForRegistration(String shortHash, int duration, int cooldown) throws CsdeException {
|
|
||||||
|
|
||||||
int timer = 0;
|
|
||||||
while (timer < duration ) {
|
|
||||||
if (checkVNodeIsRegistered(shortHash)){
|
|
||||||
pc.out.println("Vnode " + shortHash +" registered.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
utils.rpcWait(cooldown);
|
|
||||||
timer += cooldown;
|
|
||||||
}
|
|
||||||
throw new CsdeException("Vnode " + shortHash + " failed to register in " + duration + " milliseconds");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class CPIFileStatusDTO {
|
|
||||||
private String status;
|
|
||||||
private String cpiFileChecksum;
|
|
||||||
|
|
||||||
public CPIFileStatusDTO() {}
|
|
||||||
|
|
||||||
public String getStatus() { return status; }
|
|
||||||
|
|
||||||
public void setStatus(String status) { this.status = status; }
|
|
||||||
|
|
||||||
public String getCpiFileChecksum() { return cpiFileChecksum; }
|
|
||||||
|
|
||||||
public void setCpiFileChecksum(String cpiFileChecksum) { this.cpiFileChecksum = cpiFileChecksum; }
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class CpiIdentifierDTO {
|
|
||||||
|
|
||||||
// Note, these DTOs don't cover all returned values, just the ones required for CSDE
|
|
||||||
private String cpiName;
|
|
||||||
private String cpiVersion;
|
|
||||||
private String signerSummaryHash;
|
|
||||||
|
|
||||||
public CpiIdentifierDTO() { }
|
|
||||||
|
|
||||||
public String getCpiName() { return cpiName; }
|
|
||||||
|
|
||||||
public void setCpiName(String cpiName) { this.cpiName = cpiName; }
|
|
||||||
|
|
||||||
public String getCpiVersion() { return cpiVersion; }
|
|
||||||
|
|
||||||
public void setCpiVersion(String cpiVersion) { this.cpiVersion = cpiVersion; }
|
|
||||||
|
|
||||||
public String getSignerSummaryHash() { return signerSummaryHash; }
|
|
||||||
|
|
||||||
public void setSignerSummaryHash(String signerSummaryHash) { this.signerSummaryHash = signerSummaryHash; }
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class CpiMetadataDTO {
|
|
||||||
// Note, these DTOs don't cover all returned values, just the ones required for CSDE.
|
|
||||||
private String cpiFileChecksum;
|
|
||||||
private CpiIdentifierDTO id;
|
|
||||||
|
|
||||||
public CpiMetadataDTO() {}
|
|
||||||
|
|
||||||
public String getCpiFileChecksum() { return cpiFileChecksum; }
|
|
||||||
|
|
||||||
public void setCpiFileChecksum(String cpiFileChecksum) { this.cpiFileChecksum = cpiFileChecksum; }
|
|
||||||
|
|
||||||
public CpiIdentifierDTO getId() { return id; }
|
|
||||||
|
|
||||||
public void setId(CpiIdentifierDTO id) { this.id = id; }
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GetCPIsResponseDTO {
|
|
||||||
|
|
||||||
private List<CpiMetadataDTO> cpis;
|
|
||||||
|
|
||||||
public GetCPIsResponseDTO() {}
|
|
||||||
|
|
||||||
public List<CpiMetadataDTO> getCpis() { return cpis; }
|
|
||||||
|
|
||||||
public void setCpis(List<CpiMetadataDTO> cpis) { this.cpis = cpis; }
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class HoldingIdentityDTO {
|
|
||||||
// Note, these DTOs don't cover all returned values, just the ones required for CSDE.
|
|
||||||
private String fullHash;
|
|
||||||
private String groupId;
|
|
||||||
private String shortHash;
|
|
||||||
private String x500Name;
|
|
||||||
|
|
||||||
public HoldingIdentityDTO() {}
|
|
||||||
|
|
||||||
public String getFullHash() { return fullHash; }
|
|
||||||
|
|
||||||
public void setFullHash(String fullHash) { this.fullHash = fullHash; }
|
|
||||||
|
|
||||||
public String getGroupId() { return groupId; }
|
|
||||||
|
|
||||||
public void setGroupID(String groupID) { this.groupId = groupId; }
|
|
||||||
|
|
||||||
public String getShortHash() { return shortHash; }
|
|
||||||
|
|
||||||
public void setShortHash(String shortHash) { this.shortHash = shortHash; }
|
|
||||||
|
|
||||||
public String getX500Name() { return x500Name; }
|
|
||||||
|
|
||||||
public void setX500Name(String x500Name) { this.x500Name = x500Name; }
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class RegistrationRequestProgressDTO {
|
|
||||||
// Note, these DTOs don't cover all returned values, just the ones required for CSDE.
|
|
||||||
private String registrationStatus;
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
public RegistrationRequestProgressDTO() {}
|
|
||||||
|
|
||||||
public String getRegistrationStatus() { return registrationStatus; }
|
|
||||||
|
|
||||||
public void setRegistrationStatus(String registrationStatus) { this.registrationStatus = registrationStatus; }
|
|
||||||
|
|
||||||
public String getReason() { return reason; }
|
|
||||||
|
|
||||||
public void setReason(String reason) { this.reason = reason; }
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
public class VirtualNodeInfoDTO {
|
|
||||||
// Note, these DTOs don't cover all returned values, just the ones required for CSDE.
|
|
||||||
private HoldingIdentityDTO holdingIdentity;
|
|
||||||
private CpiIdentifierDTO cpiIdentifier;
|
|
||||||
|
|
||||||
public VirtualNodeInfoDTO() {}
|
|
||||||
|
|
||||||
public HoldingIdentityDTO getHoldingIdentity() { return holdingIdentity; }
|
|
||||||
|
|
||||||
public void setHoldingIdentity(HoldingIdentityDTO holdingIdentity) { this.holdingIdentity = holdingIdentity; }
|
|
||||||
|
|
||||||
public CpiIdentifierDTO getCpiIdentifier() { return cpiIdentifier; }
|
|
||||||
|
|
||||||
public void setCpiIdentifier(CpiIdentifierDTO cpiIdentifier) { this.cpiIdentifier = cpiIdentifier; }
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
package com.r3.csde.dtos;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class VirtualNodesDTO {
|
|
||||||
|
|
||||||
private List<VirtualNodeInfoDTO> virtualNodes;
|
|
||||||
|
|
||||||
public VirtualNodesDTO() {}
|
|
||||||
|
|
||||||
public List<VirtualNodeInfoDTO> getVirtualNodes() { return virtualNodes; }
|
|
||||||
|
|
||||||
public void setVirtualNodes(List<VirtualNodeInfoDTO> virtualNodes) { this.virtualNodes = virtualNodes; }
|
|
||||||
}
|
|
@ -1,23 +1,23 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"x500Name" : "CN=Alice, OU=Test Dept, O=R3, L=London, C=GB",
|
"x500Name" : "CN=Alice, OU=Test Dept, O=R3, L=London, C=GB",
|
||||||
"cpi" : "cpi name"
|
"cpi" : "MyCorDapp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x500Name" : "CN=Bob, OU=Test Dept, O=R3, L=London, C=GB",
|
"x500Name" : "CN=Bob, OU=Test Dept, O=R3, L=London, C=GB",
|
||||||
"cpi" : "cpi name"
|
"cpi" : "MyCorDapp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x500Name" : "CN=Charlie, OU=Test Dept, O=R3, L=London, C=GB",
|
"x500Name" : "CN=Charlie, OU=Test Dept, O=R3, L=London, C=GB",
|
||||||
"cpi" : "cpi name"
|
"cpi" : "MyCorDapp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x500Name" : "CN=Dave, OU=Test Dept, O=R3, L=London, C=GB",
|
"x500Name" : "CN=Dave, OU=Test Dept, O=R3, L=London, C=GB",
|
||||||
"cpi" : "cpi name"
|
"cpi" : "MyCorDapp"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"x500Name" : "CN=NotaryRep1, OU=Test Dept, O=R3, L=London, C=GB",
|
"x500Name" : "CN=NotaryRep1, OU=Test Dept, O=R3, L=London, C=GB",
|
||||||
"cpi" : "CSDE Notary Server CPI",
|
"cpi" : "NotaryServer",
|
||||||
"serviceX500Name": "CN=NotaryService, OU=Test Dept, O=R3, L=London, C=GB"
|
"serviceX500Name": "CN=NotaryService, OU=Test Dept, O=R3, L=London, C=GB"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -4,10 +4,6 @@ kotlin.code.style=official
|
|||||||
# This needs to match the version supported by the Corda Cluster the CorDapp will run on.
|
# This needs to match the version supported by the Corda Cluster the CorDapp will run on.
|
||||||
cordaApiVersion=5.0.0.665-Gecko1.0
|
cordaApiVersion=5.0.0.665-Gecko1.0
|
||||||
|
|
||||||
# Settings For Development Utilities
|
|
||||||
combinedWorkerVersion=5.0.0.0-Gecko1.0
|
|
||||||
simulatorVersion=5.0.0.0-Gecko1.0
|
|
||||||
|
|
||||||
# Specify the version of the notary plugins to use.
|
# Specify the version of the notary plugins to use.
|
||||||
# Currently packaged as part of corda-runtime-os, so should be set to a corda-runtime-os version.
|
# Currently packaged as part of corda-runtime-os, so should be set to a corda-runtime-os version.
|
||||||
cordaNotaryPluginsVersion=5.0.0.0-Gecko1.0
|
cordaNotaryPluginsVersion=5.0.0.0-Gecko1.0
|
||||||
@ -15,6 +11,9 @@ cordaNotaryPluginsVersion=5.0.0.0-Gecko1.0
|
|||||||
# Specify the version of the cordapp-cpb and cordapp-cpk plugins
|
# Specify the version of the cordapp-cpb and cordapp-cpk plugins
|
||||||
cordaPluginsVersion=7.0.1
|
cordaPluginsVersion=7.0.1
|
||||||
|
|
||||||
|
# Specify the version of the CSDE gradle plugin to use
|
||||||
|
csdePluginVersion=1.0.+
|
||||||
|
|
||||||
# For the time being this just needs to be set to a dummy value.
|
# For the time being this just needs to be set to a dummy value.
|
||||||
platformVersion = 999
|
platformVersion = 999
|
||||||
|
|
||||||
@ -31,15 +30,7 @@ mockitoKotlinVersion=4.0.0
|
|||||||
mockitoVersion=4.6.1
|
mockitoVersion=4.6.1
|
||||||
hamcrestVersion=2.2
|
hamcrestVersion=2.2
|
||||||
|
|
||||||
postgresqlVersion=42.4.3
|
|
||||||
|
|
||||||
cordaClusterURL=https://localhost:8888
|
|
||||||
cordaRpcUser=admin
|
|
||||||
cordaRpcPasswd=admin
|
|
||||||
devEnvWorkspace=workspace
|
|
||||||
dbContainerName=CSDEpostgresql
|
|
||||||
|
|
||||||
# R3 internal repository
|
# R3 internal repository
|
||||||
#S3 version for HC and RC versions published by CD/CD team
|
# Use this version when pointing to artefacts in artifactory that have not been published to S3
|
||||||
artifactoryContextUrl=https://staging.download.corda.net/maven/20ede3c6-29c0-11ed-966d-b7c36748b9f6-Gecko-RC03/
|
artifactoryContextUrl=https://software.r3.com/artifactory
|
||||||
#artifactoryContextUrl=https://staging.download.corda.net/maven/20ede3c6-29c0-11ed-966d-b7c36748b9f6-Gecko-RC02/
|
|
@ -3,8 +3,16 @@ pluginManagement {
|
|||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
mavenLocal()
|
||||||
maven {
|
maven {
|
||||||
url = "$artifactoryContextUrl/"
|
url = "$artifactoryContextUrl/corda-os-maven"
|
||||||
|
authentication {
|
||||||
|
basic(BasicAuthentication)
|
||||||
|
}
|
||||||
|
credentials {
|
||||||
|
username = settings.ext.find('cordaArtifactoryUsername') ?: System.getenv('CORDA_ARTIFACTORY_USERNAME')
|
||||||
|
password = settings.ext.find('cordaArtifactoryPassword') ?: System.getenv('CORDA_ARTIFACTORY_PASSWORD')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,6 +22,7 @@ pluginManagement {
|
|||||||
id 'net.corda.plugins.cordapp-cpk2' version cordaPluginsVersion
|
id 'net.corda.plugins.cordapp-cpk2' version cordaPluginsVersion
|
||||||
id 'net.corda.plugins.cordapp-cpb2' version cordaPluginsVersion
|
id 'net.corda.plugins.cordapp-cpb2' version cordaPluginsVersion
|
||||||
id 'net.corda.cordapp.cordapp-configuration' version cordaApiVersion
|
id 'net.corda.cordapp.cordapp-configuration' version cordaApiVersion
|
||||||
|
id 'net.corda.plugins.csde' version csdePluginVersion
|
||||||
id 'org.jetbrains.kotlin.jvm' version kotlinVersion
|
id 'org.jetbrains.kotlin.jvm' version kotlinVersion
|
||||||
id 'org.jetbrains.kotlin.plugin.jpa' version kotlinVersion
|
id 'org.jetbrains.kotlin.plugin.jpa' version kotlinVersion
|
||||||
id 'org.jetbrains.kotlin.plugin.allopen' version kotlinVersion
|
id 'org.jetbrains.kotlin.plugin.allopen' version kotlinVersion
|
||||||
|
Loading…
Reference in New Issue
Block a user