From 2cd1fb237b0d38745a8fc19864d04cb3dc9c9f4c Mon Sep 17 00:00:00 2001 From: Peter Somogyvari Date: Tue, 13 Feb 2024 15:48:07 -0800 Subject: [PATCH] test(tools/docker): add new Corda v4.12-SNAPSHOT all-in-one image Published on GHCR as `ghcr.io/hyperledger/cactus-corda-4-12-all-in-one-negotiation:2024-02-13-dev` 1. It is a more bare bones flavor of the previous versions in the sense that it does not support running the REST API web servers that come with the samples repository at all. It only supports running the nodes A, B and Notary. 2. There is no Party C because we had to switch over to the negotiation-cordapp example. 3. This flavor of the image supports customizing the log levels of the Corda node through the file at: tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/log4j2.xml Note however that applying these changes requires a rebuild of the image so it's still less convenient than idea lto use, but at least now we have an option to do so. 4. Another new feature of this image compared to the earlier Corda AIO images is that it uses Ubuntu 22.04 LTS as it's base instead of alpine. This increases the image size a little but it's well worth the trade-off of having a uniform image base (which is the long term plan) 5. There is a builder stage that can be used to clone an arbitrary branch + SHA combination of the upstream corda git repository and then build the node .jar file from it which then will be used by the image to run the nodes. The custom-built .jar file is placed under /opt/bin/corda.jar so do not mix that one up with the other one that is provided with the corda kotlin-samples repo. 6. The `run-notary-node.sh`, `run-party-a-node.sh` and `run-party-b-node.sh` scripts were altered to use the custom-built .jar file mentioned above and this is the reason why this commit adds a (seeming) clone of these scripts. 7. For now I did not add a CI task for building and publishing the image because even though that would match the older images, I'm trying to save on CI resources and at the moment we don't necessarily need a fresh build of this image on each new pull request. 8. Last but not least (first actually) this is also a security adjacent upgrade since using this image is the precursor to a much bigger change that will see the Corda v4 connector's dependencies upgraded to Spring Boot v3 and Corda v4.12-SNAPSHOT but we can't do that without having this image published first if we want to have test-automation verifying those changes. Signed-off-by: Peter Somogyvari --- tools/docker/corda-all-in-one/README.md | 15 ++ .../corda-all-in-one/corda-v4_12/Dockerfile | 118 +++++++++++++ .../corda-v4_12/healthcheck.sh | 26 +++ .../negotiation-cordapp/build.gradle | 161 ++++++++++++++++++ .../negotiation-cordapp/log4j2.xml | 63 +++++++ .../corda-v4_12/run-notary-node.sh | 13 ++ .../corda-v4_12/run-party-a-node.sh | 13 ++ .../corda-v4_12/run-party-b-node.sh | 13 ++ .../corda-v4_12/supervisord.conf | 60 +++++++ 9 files changed, 482 insertions(+) create mode 100644 tools/docker/corda-all-in-one/corda-v4_12/Dockerfile create mode 100755 tools/docker/corda-all-in-one/corda-v4_12/healthcheck.sh create mode 100644 tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/build.gradle create mode 100644 tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/log4j2.xml create mode 100755 tools/docker/corda-all-in-one/corda-v4_12/run-notary-node.sh create mode 100755 tools/docker/corda-all-in-one/corda-v4_12/run-party-a-node.sh create mode 100755 tools/docker/corda-all-in-one/corda-v4_12/run-party-b-node.sh create mode 100644 tools/docker/corda-all-in-one/corda-v4_12/supervisord.conf diff --git a/tools/docker/corda-all-in-one/README.md b/tools/docker/corda-all-in-one/README.md index 3890bb6467..7ba5dd1331 100644 --- a/tools/docker/corda-all-in-one/README.md +++ b/tools/docker/corda-all-in-one/README.md @@ -48,6 +48,21 @@ DOCKER_BUILDKIT=1 docker build ./tools/docker/corda-all-in-one/corda-v4_8-flowdb docker run --rm --privileged caio48-flowdb ``` +# cactus-corda-4-12-all-in-one + +> This docker image is for `testing` and `development` only. +> Do NOT use in production! + +## Usage + +### Build and Run Image Locally + +```sh +DOCKER_BUILDKIT=1 docker build ./tools/docker/corda-all-in-one/corda-v4_12/ -f ./tools/docker/corda-all-in-one/corda-v4_12/Dockerfile -t caio412 +docker run --rm --privileged caio412 +``` + + # cactus-corda-5-all-in-one-solar > This docker image is for `testing` and `development` only. diff --git a/tools/docker/corda-all-in-one/corda-v4_12/Dockerfile b/tools/docker/corda-all-in-one/corda-v4_12/Dockerfile new file mode 100644 index 0000000000..893dba2c2e --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/Dockerfile @@ -0,0 +1,118 @@ +FROM ubuntu:22.04 as builder + +RUN apt update && apt install openjdk-17-jdk git curl augeas-tools -y +WORKDIR /opt/ +RUN git clone https://github.com/corda/corda.git +WORKDIR /opt/corda/ + +# commit c7514e1c603c077b49987fd79bd77060612967ed (HEAD -> release/os/4.12, upstream/release/os/4.12) +# Author: Chris Cochrane <78791827+chriscochrane@users.noreply.github.com> +# Date: Wed Feb 7 14:46:18 2024 +0000 +# +# ENT-11443 Function sig changes to support removing enterprise compiler warnings (#7671) +RUN git switch release/os/4.12 +RUN git checkout c7514e1c603c077b49987fd79bd77060612967ed +RUN ./gradlew jar -x test + +FROM ubuntu:22.04 + +RUN apt update && apt install openjdk-17-jdk supervisor openssh-server sudo git curl iputils-ping netcat augeas-tools -y + +RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1000 test + +RUN echo 'root:root' | chpasswd + +RUN mkdir /var/run/sshd + +ARG CORDA_TOOLS_SHELL_CLI_VERSION=4.8.11 + +WORKDIR / + +ENV CACTUS_CFG_PATH=/etc/hyperledger/cactus +RUN mkdir -p $CACTUS_CFG_PATH + +RUN curl https://download.corda.net/maven/corda-releases/net/corda/corda-tools-shell-cli/${CORDA_TOOLS_SHELL_CLI_VERSION}/corda-tools-shell-cli-${CORDA_TOOLS_SHELL_CLI_VERSION}-all.jar --output /corda-tools-shell-cli-all.jar +# Make the "corda-shell" alias avaialble on the terminal +RUN java -jar /corda-tools-shell-cli-all.jar install-shell-extensions + +# The image has a bleeding edge version of corda baked in for testing conveniece +RUN mkdir -p /opt/bin/ +COPY --from=builder /opt/corda/node/capsule/build/libs/corda-4.12-SNAPSHOT.jar /opt/bin/corda.jar + +RUN git clone https://github.com/corda/samples-kotlin.git +WORKDIR /samples-kotlin + +ARG SAMPLES_KOTLIN_SHA=219750f8da2fd491c3b55c8eea821b1f345fef7d +ARG SAMPLES_KOTLIN_BRANCH=arshadm/ent-6914-upgrade-kotlin19-jdk17 + +RUN git switch ${SAMPLES_KOTLIN_BRANCH} +RUN git checkout ${SAMPLES_KOTLIN_SHA} + +ARG SAMPLES_KOTLIN_CORDAPP_SUB_DIR_PATH="./Advanced/negotiation-cordapp/" +WORKDIR /samples-kotlin/${SAMPLES_KOTLIN_CORDAPP_SUB_DIR_PATH} + +COPY ./negotiation-cordapp/build.gradle /samples-kotlin/Advanced/negotiation-cordapp/build.gradle + +RUN ./gradlew build deployNodes + +WORKDIR / + +# Configure the OpenSSH server we just installed +RUN augtool 'set /files/etc/ssh/sshd_config/AuthorizedKeysFile ".ssh/authorized_keys /etc/authorized_keys/%u"' && \ + augtool 'set /files/etc/ssh/sshd_config/PermitRootLogin yes' && \ + augtool 'set /files/etc/ssh/sshd_config/PasswordAuthentication yes' && \ + augtool 'set /files/etc/ssh/sshd_config/PermitEmptyPasswords yes' && \ + augtool 'set /files/etc/ssh/sshd_config/Port 22' && \ + augtool 'set /files/etc/ssh/sshd_config/LogLevel DEBUG2' && \ + augtool 'set /files/etc/ssh/sshd_config/LoginGraceTime 10' + +# Create the server's key - without this sshd will refuse to start +RUN ssh-keygen -A + +# Generate an RSA keypair on the fly to avoid having to hardcode one in the image +# which technically does not pose a security threat since this is only a development +# image, but we do it like this anyway. +RUN mkdir ~/.ssh && \ + chmod 700 ~/.ssh/ && \ + touch ~/.ssh/authorized_keys + +RUN ["/bin/bash", "-c", "ssh-keygen -t rsa -N '' -f $CACTUS_CFG_PATH/corda-aio-image"] +RUN mv $CACTUS_CFG_PATH/corda-aio-image $CACTUS_CFG_PATH/corda-aio-image.key +RUN cp $CACTUS_CFG_PATH/corda-aio-image.pub ~/.ssh/authorized_keys + +WORKDIR /samples-kotlin/${SAMPLES_KOTLIN_CORDAPP_SUB_DIR_PATH} + +# OpenSSH server +EXPOSE 22 + +# supervisord web ui/dashboard +EXPOSE 9001 + +# Party Notary, Party A, Party B RPC ports +EXPOSE 10003 10006 10009 + +# Jolokia for Party A,B,C and Notary +EXPOSE 7005 7006 7007 7008 + +# JVM remote debug port +EXPOSE 5005 5006 5008 + +COPY supervisord.conf /etc/supervisord.conf +COPY run-party-b-node.sh run-notary-node.sh healthcheck.sh run-party-a-node.sh / +COPY ./negotiation-cordapp/log4j2.xml /samples-kotlin/Advanced/negotiation-cordapp/config/dev/log4j2.xml + +# By default we only run the absolute minimum which is a single partys node. +# For more complex tests everything else can also be enabled via the env vars +# below so that if needed there is 2 parties, a notary and a dedicated web server +# for all 3 of those nodes. +# "Web server" => the same one as in the official corda samples-kotlin repo +ENV PARTY_A_NODE_ENABLED="true" + +ENV PARTY_B_NODE_ENABLED="true" + +ENV NOTARY_NODE_ENABLED="true" + +ENTRYPOINT ["/usr/bin/supervisord"] +CMD ["--configuration", "/etc/supervisord.conf", "--nodaemon"] + +HEALTHCHECK --interval=1s --timeout=5s --start-period=5s --retries=120 CMD /healthcheck.sh diff --git a/tools/docker/corda-all-in-one/corda-v4_12/healthcheck.sh b/tools/docker/corda-all-in-one/corda-v4_12/healthcheck.sh new file mode 100755 index 0000000000..96b8975722 --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/healthcheck.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +if [ "$PARTY_A_WEB_SRV_ENABLED" = "true" ] +then + curl -vv -i -X OPTIONS http://127.0.0.1:10009/web/iou/ +fi + +if [ "$PARTY_B_WEB_SRV_ENABLED" = "true" ] +then + curl -vv -i -X OPTIONS http://127.0.0.1:10012/web/iou/ +fi + + +if [ "$PARTY_A_NODE_ENABLED" = "true" ] +then + curl -v 'http://localhost:7005/jolokia/exec/org.apache.activemq.artemis:address=%22rpc.server%22,broker=%22RPC%22,component=addresses,queue=%22rpc.server%22,routing-type=%22multicast%22,subcomponent=queues/countMessages()/' +fi + +if [ "$PARTY_B_NODE_ENABLED" = "true" ] +then + curl -v 'http://localhost:7006/jolokia/exec/org.apache.activemq.artemis:address=%22rpc.server%22,broker=%22RPC%22,component=addresses,queue=%22rpc.server%22,routing-type=%22multicast%22,subcomponent=queues/countMessages()/' +fi + +curl -v 'http://localhost:7008/jolokia/exec/org.apache.activemq.artemis:address=%22rpc.server%22,broker=%22RPC%22,component=addresses,queue=%22rpc.server%22,routing-type=%22multicast%22,subcomponent=queues/countMessages()/' diff --git a/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/build.gradle b/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/build.gradle new file mode 100644 index 0000000000..70235fb10a --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/build.gradle @@ -0,0 +1,161 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +import static org.gradle.api.JavaVersion.VERSION_17 +import static org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 +import static org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8 + +buildscript { //properties that you need to build the project + + Properties constants = new Properties() + file("$projectDir/../constants.properties").withInputStream { constants.load(it) } + + ext { + corda_release_group = constants.getProperty("cordaReleaseGroup") + corda_core_release_group = constants.getProperty("cordaCoreReleaseGroup") + corda_release_version = constants.getProperty("cordaVersion") + corda_shell_version = corda_release_version + corda_core_release_version = constants.getProperty("cordaCoreVersion") + corda_gradle_plugins_version = constants.getProperty("gradlePluginsVersion") + kotlin_version = constants.getProperty("kotlinVersion") + junit_version = constants.getProperty("junitVersion") + quasar_version = constants.getProperty("quasarVersion") + log4j_version = constants.getProperty("log4jVersion") + slf4j_version = constants.getProperty("slf4jVersion") + corda_platform_version = constants.getProperty("platformVersion").toInteger() + rxjava_version = constants.getProperty("rxJavaVersion") + snappy_version = constants.getProperty("snappyVersion") + //springboot + spring_boot_version = '2.0.2.RELEASE' + spring_boot_gradle_plugin_version = '2.0.2.RELEASE' + + testJvmArgs = ['--add-opens', 'java.base/java.time=ALL-UNNAMED', '--add-opens', 'java.base/java.io=ALL-UNNAMED', + '--add-opens', 'java.base/java.util=ALL-UNNAMED', '--add-opens', 'java.base/java.net=ALL-UNNAMED', + '--add-opens', 'java.base/java.nio=ALL-UNNAMED', '--add-opens', 'java.base/java.lang.invoke=ALL-UNNAMED', + '--add-opens', 'java.base/java.security.cert=ALL-UNNAMED', '--add-opens', 'java.base/java.security=ALL-UNNAMED', + '--add-opens', 'java.base/javax.net.ssl=ALL-UNNAMED', '--add-opens', 'java.base/java.lang=ALL-UNNAMED', + '--add-opens', 'java.base/java.util.concurrent=ALL-UNNAMED', '--add-opens', 'java.sql/java.sql=ALL-UNNAMED',] + testJvmFxArgs = [ '--add-exports', 'java.base/sun.nio.ch=ALL-UNNAMED', + '--add-exports', 'javafx.base/com.sun.javafx=ALL-UNNAMED', + '--add-exports', 'javafx.base/com.sun.javafx.collections=ALL-UNNAMED'] + } + + repositories { + mavenLocal() + mavenCentral() + + maven { url 'https://download.corda.net/maven/corda-releases' } + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "net.corda.plugins:cordapp:$corda_gradle_plugins_version" + classpath "net.corda.plugins:cordformation:$corda_gradle_plugins_version" + classpath "net.corda.plugins:quasar-utils:$corda_gradle_plugins_version" + classpath "org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_gradle_plugin_version" + } +} + +allprojects { //Properties that you need to compile your project (The application) + apply from: "${rootProject.projectDir}/repositories.gradle" + apply plugin: 'org.jetbrains.kotlin.jvm' + + repositories { + mavenLocal() + maven { url 'https://download.corda.net/maven/corda-releases' } + mavenCentral() + maven { url 'https://download.corda.net/maven/corda-dependencies' } + maven { url 'https://jitpack.io' } + } + + tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile) { + compilerOptions { + languageVersion = KOTLIN_1_8 + apiVersion = KOTLIN_1_8 + jvmTarget = JVM_17 + javaParameters = true // Useful for reflection. + freeCompilerArgs = ['-Xjvm-default=all-compatibility'] + allWarningsAsErrors = true + } + } + + jar { + // This makes the JAR's SHA-256 hash repeatable. + preserveFileTimestamps = false + reproducibleFileOrder = true + } +} + +apply plugin: 'net.corda.plugins.cordapp' +apply plugin: 'net.corda.plugins.cordformation' +apply plugin: 'net.corda.plugins.quasar-utils' + +sourceSets { + main { + resources { + srcDir rootProject.file("config/dev") + } + } +} + +//Module dependencis +dependencies { + // Corda dependencies. + cordaProvided "$corda_release_group:corda-core:$corda_release_version" + cordaBootstrapper("$corda_release_group:corda-node-api:$corda_release_version") { + exclude group: "ch.qos.logback", module: "logback-classic" + } + corda "$corda_release_group:corda:$corda_release_version" + + // CorDapp dependencies. + cordapp("$corda_release_group:corda-finance-contracts:$corda_release_version") + cordapp("$corda_release_group:corda-finance-workflows:$corda_release_version") + cordapp project(":workflows") + cordapp project(":contracts") + + cordaProvided "org.apache.logging.log4j:log4j-slf4j-impl:${log4j_version}" + cordaProvided "org.apache.logging.log4j:log4j-web:${log4j_version}" + cordaProvided "org.slf4j:jul-to-slf4j:$slf4j_version" + cordaDriver "net.corda:corda-shell:$corda_shell_version" +} + +cordapp { + targetPlatformVersion corda_platform_version.toInteger() + minimumPlatformVersion corda_platform_version.toInteger() +} + + +task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar']) { + nodeDefaults { + + cordapp project(':contracts') + cordapp project(':workflows') + runSchemaMigration = true + } + node { + name "O=Notary,L=London,C=GB" + notary = [validating : false] + p2pPort 10002 + rpcSettings { + address("0.0.0.0:10003") + adminAddress("0.0.0.0:10043") + } + } + node { + name "O=PartyA,L=London,C=GB" + p2pPort 10005 + rpcSettings { + address("0.0.0.0:10006") + adminAddress("0.0.0.0:10046") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } + node { + name "O=PartyB,L=New York,C=US" + p2pPort 10008 + rpcSettings { + address("0.0.0.0:10009") + adminAddress("0.0.0.0:10049") + } + rpcUsers = [[ user: "user1", "password": "test", "permissions": ["ALL"]]] + } +} diff --git a/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/log4j2.xml b/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/log4j2.xml new file mode 100644 index 0000000000..5aae263c69 --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/negotiation-cordapp/log4j2.xml @@ -0,0 +1,63 @@ + + + + + logs + node-${hostName} + ${log-path}/archive + + + + + + + + + %highlight{%level{length=1} %d{HH:mm:ss} %T %c{1}.%M - %msg%n}{INFO=white,WARN=red,FATAL=bright red blink} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/docker/corda-all-in-one/corda-v4_12/run-notary-node.sh b/tools/docker/corda-all-in-one/corda-v4_12/run-notary-node.sh new file mode 100755 index 0000000000..add8399b78 --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/run-notary-node.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e + +if [ "$NOTARY_NODE_ENABLED" = "true" ] +then + java \ + -Dcapsule.jvm.args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5008 -javaagent:drivers/jolokia-jvm-1.6.2-agent.jar=port=7008,logHandlerClass=net.corda.node.JolokiaSlf4jAdapter" \ + -Dname=Notary \ + -Dlog4j2.configurationFile=/samples-kotlin/Advanced/negotiation-cordapp/config/dev/log4j2.xml \ + -jar /opt/bin/corda.jar +else + sleep infinity +fi diff --git a/tools/docker/corda-all-in-one/corda-v4_12/run-party-a-node.sh b/tools/docker/corda-all-in-one/corda-v4_12/run-party-a-node.sh new file mode 100755 index 0000000000..2384e75635 --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/run-party-a-node.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e + +if [ "$PARTY_A_NODE_ENABLED" = "true" ] +then + java \ + -Dcapsule.jvm.args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -javaagent:drivers/jolokia-jvm-1.6.2-agent.jar=port=7005,logHandlerClass=net.corda.node.JolokiaSlf4jAdapter" \ + -Dname=PartyA \ + -Dlog4j2.configurationFile=/samples-kotlin/Advanced/negotiation-cordapp/config/dev/log4j2.xml \ + -jar /opt/bin/corda.jar +else + sleep infinity +fi diff --git a/tools/docker/corda-all-in-one/corda-v4_12/run-party-b-node.sh b/tools/docker/corda-all-in-one/corda-v4_12/run-party-b-node.sh new file mode 100755 index 0000000000..50024d6cff --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/run-party-b-node.sh @@ -0,0 +1,13 @@ +#!/bin/sh +set -e + +if [ "$PARTY_B_NODE_ENABLED" = "true" ] +then + java \ + -Dcapsule.jvm.args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5006 -javaagent:drivers/jolokia-jvm-1.6.2-agent.jar=port=7006,logHandlerClass=net.corda.node.JolokiaSlf4jAdapter" \ + -Dname=PartyB \ + -Dlog4j2.configurationFile=/samples-kotlin/Advanced/negotiation-cordapp/config/dev/log4j2.xml \ + -jar /opt/bin/corda.jar +else + sleep infinity +fi diff --git a/tools/docker/corda-all-in-one/corda-v4_12/supervisord.conf b/tools/docker/corda-all-in-one/corda-v4_12/supervisord.conf new file mode 100644 index 0000000000..596c19eae7 --- /dev/null +++ b/tools/docker/corda-all-in-one/corda-v4_12/supervisord.conf @@ -0,0 +1,60 @@ +[supervisord] +logfile = /var/log/supervisord.log +logfile_maxbytes = 50MB +logfile_backups=10 +loglevel = info + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=http://127.0.0.1:9001 + +[inet_http_server] +port = 0.0.0.0:9001 + +[program:sshd] +command=/usr/sbin/sshd -D -ddd +autostart=true +autorestart=true +stdout_logfile=/var/log/sshd.out.log +stderr_logfile=/var/log/sshd.err.log +; stdout_logfile=/dev/stdout +; stdout_logfile_maxbytes=0 +; stderr_logfile=/dev/stderr +; stderr_logfile_maxbytes=0 + + +[program:corda-a] +directory=/samples-kotlin/Advanced/negotiation-cordapp/build/nodes/PartyA/ +command=/run-party-a-node.sh +autostart=true +autorestart=false +exitcodes=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:corda-b] +directory=/samples-kotlin/Advanced/negotiation-cordapp/build/nodes/PartyB +command=/run-party-b-node.sh +autostart=true +autorestart=false +exitcodes=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:corda-n] +directory=/samples-kotlin/Advanced/negotiation-cordapp/build/nodes/Notary +command=/run-notary-node.sh +autostart=true +autorestart=false +exitcodes=0 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +