mirror of https://github.com/hyperledger/besu
[NC-1646] Removed system/smoke tests + resources. (#32)
parent
90705bbcb9
commit
591a9c9979
@ -1,41 +0,0 @@ |
|||||||
dependencies { |
|
||||||
implementation 'com.github.docker-java:docker-java' |
|
||||||
implementation 'com.squareup.okhttp3:okhttp' |
|
||||||
implementation 'io.vertx:vertx-core' |
|
||||||
implementation 'org.apache.logging.log4j:log4j-api' |
|
||||||
implementation 'org.assertj:assertj-core' |
|
||||||
|
|
||||||
runtime 'org.apache.logging.log4j:log4j-core' |
|
||||||
|
|
||||||
testImplementation project(':ethereum:client') |
|
||||||
testImplementation project(':ethereum:jsonrpc') |
|
||||||
testImplementation project(':pantheon') |
|
||||||
testImplementation project(':util') |
|
||||||
|
|
||||||
testImplementation 'junit:junit' |
|
||||||
testImplementation 'org.awaitility:awaitility' |
|
||||||
} |
|
||||||
|
|
||||||
test.enabled = false |
|
||||||
|
|
||||||
task smokeTest(type: Test) { |
|
||||||
mustRunAfter rootProject.subprojects*.test |
|
||||||
description = 'Runs basic Pantheon smoke tests.' |
|
||||||
group = 'verification' |
|
||||||
systemProperty 'pantheon.test.distribution', "${buildDir}/pantheon-${project.version}" |
|
||||||
} |
|
||||||
|
|
||||||
task unpackTarDistribution(type: Copy) { |
|
||||||
dependsOn rootProject.distTar |
|
||||||
def tar = file("${projectDir}/../build/distributions/pantheon-${project.version}.tar.gz") |
|
||||||
inputs.files tar |
|
||||||
from tarTree(tar) |
|
||||||
into {buildDir} |
|
||||||
} |
|
||||||
|
|
||||||
smokeTest.dependsOn(unpackTarDistribution) |
|
||||||
smokeTest.dependsOn(rootProject.installDist) |
|
||||||
|
|
||||||
// Commenting out dependency so that check (on CircleCI won't try to run this and fail) |
|
||||||
// Jenkins can run it as a separate task. |
|
||||||
//check.dependsOn(smokeTest) |
|
@ -1,152 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests; |
|
||||||
|
|
||||||
import static java.util.stream.Collectors.joining; |
|
||||||
|
|
||||||
import net.consensys.pantheon.tests.cluster.NodeAdminRpcUtils; |
|
||||||
import net.consensys.pantheon.tests.cluster.TestCluster; |
|
||||||
import net.consensys.pantheon.tests.cluster.TestClusterNode; |
|
||||||
|
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.Date; |
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
import org.assertj.core.api.Assertions; |
|
||||||
import org.junit.BeforeClass; |
|
||||||
import org.junit.Rule; |
|
||||||
import org.junit.rules.TestRule; |
|
||||||
import org.junit.rules.TestWatcher; |
|
||||||
import org.junit.runner.Description; |
|
||||||
|
|
||||||
public abstract class ClusterTestBase { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
@Rule |
|
||||||
public TestRule watcher = |
|
||||||
new TestWatcher() { |
|
||||||
@Override |
|
||||||
protected void starting(final Description description) { |
|
||||||
LOG.info("Starting test: " + description.getMethodName()); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void finished(final Description description) { |
|
||||||
LOG.info("Finished test: " + description.getMethodName()); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
// TODO: I need to remember how I used to make this work in one shot, even with static
|
|
||||||
// @BeforeClass
|
|
||||||
protected static String suiteStartTime = null; |
|
||||||
protected static String suiteName = null; |
|
||||||
|
|
||||||
@BeforeClass |
|
||||||
public static void setTestSuiteStartTime() { |
|
||||||
final SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd-HHmmss"); |
|
||||||
suiteStartTime = fmt.format(new Date()); |
|
||||||
} |
|
||||||
|
|
||||||
public static void suiteName(final Class<?> clazz) { |
|
||||||
suiteName = clazz.getSimpleName() + "-" + suiteStartTime; |
|
||||||
} |
|
||||||
|
|
||||||
public static String suiteName() { |
|
||||||
return suiteName; |
|
||||||
} |
|
||||||
|
|
||||||
@BeforeClass |
|
||||||
public static void printSystemProperties() { |
|
||||||
final String env = |
|
||||||
System.getenv() |
|
||||||
.entrySet() |
|
||||||
.stream() |
|
||||||
.map(e -> e.getKey() + "=" + e.getValue()) |
|
||||||
.collect(joining(System.getProperty("line.separator"))); |
|
||||||
|
|
||||||
final String s = |
|
||||||
System.getProperties() |
|
||||||
.entrySet() |
|
||||||
.stream() |
|
||||||
.map(e -> e.getKey() + "=" + e.getValue()) |
|
||||||
.collect(joining(System.getProperty("line.separator"))); |
|
||||||
|
|
||||||
LOG.info("System Properties\n" + s); |
|
||||||
LOG.info("Environment\n" + env); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds and verifies a Pantheon full-node container to the cluster |
|
||||||
* |
|
||||||
* @param cluster cluster to add node to |
|
||||||
* @param containerName name to give the new container |
|
||||||
*/ |
|
||||||
protected static TestClusterNode addVerifiedPantheonCtr( |
|
||||||
final TestCluster cluster, final String containerName) throws Exception { |
|
||||||
final TestClusterNode node = cluster.addPantheonFullDockerNode(containerName); |
|
||||||
Assertions.assertThat(cluster.getNodes()).contains(node); |
|
||||||
NodeAdminRpcUtils.testWeb3ClientVersionPantheon(node); |
|
||||||
// TODO: Better verifications before handing off for testing
|
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds and verifies a Geth full-node container to the cluster |
|
||||||
* |
|
||||||
* @param cluster cluster to add node to |
|
||||||
* @param containerName name to give the new container |
|
||||||
*/ |
|
||||||
protected static TestClusterNode addVerifiedGethCtr( |
|
||||||
final TestCluster cluster, final String containerName) throws Exception { |
|
||||||
final TestClusterNode node = cluster.addGethFullDockerNode(containerName); |
|
||||||
Assertions.assertThat(cluster.getNodes()).contains(node); |
|
||||||
NodeAdminRpcUtils.testWeb3ClientVersionGeth(node); |
|
||||||
// TODO: Better verifications before handing off for testing
|
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds and verifies a Geth boot-node container to the cluster. Generally, only one is required in |
|
||||||
* the cluster, but adding more than one should not be harmful. |
|
||||||
* |
|
||||||
* @param cluster cluster to add node to |
|
||||||
* @param containerName name to give the new container |
|
||||||
*/ |
|
||||||
protected static TestClusterNode addVerifiedGethBootCtr( |
|
||||||
final TestCluster cluster, final String containerName) throws Exception { |
|
||||||
final TestClusterNode node = cluster.addGethBootDockerNode(containerName); |
|
||||||
Assertions.assertThat(cluster.getNodes()).contains(node); |
|
||||||
// TODO: Better verifications before handing off for testing
|
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds and verifies a Geth local process to the cluster. A new tmp data directory will be created |
|
||||||
* for each local process node. |
|
||||||
* |
|
||||||
* <p>TODO: Make this play nice with other nodes running in docker containers. |
|
||||||
* |
|
||||||
* @param cluster cluster to add node to |
|
||||||
* @param gethCmd path to the geth command. ie /usr/bin/geth |
|
||||||
* @param nodeNum two-digit node number. This will be used in node naming and port numbering. |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
protected static TestClusterNode addVerifiedLocalGethProcess( |
|
||||||
final TestCluster cluster, final String gethCmd, final String nodeNum) throws Exception { |
|
||||||
final TestClusterNode node = cluster.addGethLocalNode(gethCmd, nodeNum); |
|
||||||
Assertions.assertThat(cluster.getNodes()).contains(node); |
|
||||||
NodeAdminRpcUtils.testWeb3ClientVersionGeth(node); |
|
||||||
// TODO: Better verifications before handing off for testing
|
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** Helper method to stand up a private cluster. */ |
|
||||||
@SuppressWarnings("unused") |
|
||||||
private void buildVerifiedCluster( |
|
||||||
final TestCluster cluster, |
|
||||||
final int numPantheonNodes, |
|
||||||
final int numGethNodes, |
|
||||||
final int numParityNodes) { |
|
||||||
// TODO: Implement if useful
|
|
||||||
// TODO: If test times are too long, consider creating/destroying nodes in parallel
|
|
||||||
} |
|
||||||
} |
|
@ -1,86 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests; |
|
||||||
|
|
||||||
import static net.consensys.pantheon.tests.cluster.NodeAdminRpcUtils.getPeersJson; |
|
||||||
|
|
||||||
import net.consensys.pantheon.tests.cluster.TestCluster; |
|
||||||
import net.consensys.pantheon.tests.cluster.TestClusterNode; |
|
||||||
|
|
||||||
import io.vertx.core.json.JsonArray; |
|
||||||
import io.vertx.core.json.JsonObject; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
import org.junit.AfterClass; |
|
||||||
import org.junit.BeforeClass; |
|
||||||
import org.junit.Test; |
|
||||||
|
|
||||||
@SuppressWarnings("UnusedReturnValue") |
|
||||||
public class LogClusterInfoTest extends ClusterTestBase { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
protected static TestCluster testCluster; |
|
||||||
|
|
||||||
@BeforeClass |
|
||||||
public static void createCluster() throws Exception { |
|
||||||
suiteName(LogClusterInfoTest.class); |
|
||||||
try { |
|
||||||
// TODO: If test times are too long, consider creating/destroying nodes in parallel
|
|
||||||
testCluster = new TestCluster(suiteName().toLowerCase()); |
|
||||||
addVerifiedGethBootCtr(testCluster, suiteName() + "-GethBoot00"); |
|
||||||
addVerifiedGethCtr(testCluster, suiteName() + "-Geth01"); |
|
||||||
addVerifiedGethCtr(testCluster, suiteName() + "-Geth02"); |
|
||||||
addVerifiedPantheonCtr(testCluster, suiteName() + "-Pantheon01"); |
|
||||||
addVerifiedPantheonCtr(testCluster, suiteName() + "-Pantheon02"); |
|
||||||
// addVerifiedLocalGethProcess(cluster, "/usr/bin/geth", "04");
|
|
||||||
Thread.sleep(2_000); // Wait for everything to settle
|
|
||||||
} catch (final Exception e) { |
|
||||||
LOG.error("Unable to build private test cluster.", e); |
|
||||||
throw e; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@AfterClass |
|
||||||
public static void destroyCluster() { |
|
||||||
try { |
|
||||||
testCluster.close(); |
|
||||||
} catch (final Exception e) { |
|
||||||
LOG.error("Error destroying cluster. Ignoring and continuing. cluster=" + testCluster, e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void logClusterInfo() throws Exception { |
|
||||||
LOG.info("Cluster: " + testCluster); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void logPeerPorts() throws Exception { |
|
||||||
for (final TestClusterNode node : testCluster.getNodes()) { |
|
||||||
if (node.isBootNode()) { |
|
||||||
continue; // Skip it. Boot nodes don't have any interfaces to query
|
|
||||||
} |
|
||||||
LOG.info("node=" + node); |
|
||||||
final JsonArray peersJson = getPeersJson(node); |
|
||||||
for (int i = 0; i < peersJson.size(); i++) { |
|
||||||
final JsonObject network = peersJson.getJsonObject(i).getJsonObject("network"); |
|
||||||
final String local = network.getString("localAddress"); |
|
||||||
final String remote = network.getString("remoteAddress"); |
|
||||||
LOG.info( |
|
||||||
String.format( |
|
||||||
"Node %s discovered peer: local port %s, remote port %s", |
|
||||||
node.getNodeName(), local, remote)); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void logAdminPeers() throws Exception { |
|
||||||
for (final TestClusterNode node : testCluster.getNodes()) { |
|
||||||
if (node.isBootNode()) { |
|
||||||
continue; // Skip it. Boot nodes don't have any interfaces to query
|
|
||||||
} |
|
||||||
LOG.info( |
|
||||||
String.format( |
|
||||||
"Node %s Admin.Peers:\n%s", node.getNodeName(), getPeersJson(node).encodePrettily())); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,101 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests; |
|
||||||
|
|
||||||
import static com.google.common.io.MoreFiles.deleteDirectoryContents; |
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
|
|
||||||
import net.consensys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.net.HttpURLConnection; |
|
||||||
import java.net.InetAddress; |
|
||||||
import java.net.Socket; |
|
||||||
import java.nio.file.Files; |
|
||||||
import java.nio.file.Path; |
|
||||||
import java.nio.file.Paths; |
|
||||||
import java.util.concurrent.TimeUnit; |
|
||||||
|
|
||||||
import com.google.common.io.RecursiveDeleteOption; |
|
||||||
import io.vertx.core.json.Json; |
|
||||||
import okhttp3.MediaType; |
|
||||||
import okhttp3.OkHttpClient; |
|
||||||
import okhttp3.Request; |
|
||||||
import okhttp3.RequestBody; |
|
||||||
import okhttp3.Response; |
|
||||||
import org.awaitility.Awaitility; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Rule; |
|
||||||
import org.junit.Test; |
|
||||||
import org.junit.rules.TemporaryFolder; |
|
||||||
|
|
||||||
public final class PantheonSmokeTest { |
|
||||||
|
|
||||||
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); |
|
||||||
|
|
||||||
private Path pantheonBin; |
|
||||||
|
|
||||||
@Before |
|
||||||
public void before() throws IOException { |
|
||||||
final String dist = System.getProperty("pantheon.test.distribution"); |
|
||||||
if (dist == null) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"System property 'pantheon.test.distribution' must be set in order for this test to work."); |
|
||||||
} |
|
||||||
final Path pantheonBase = Paths.get(dist); |
|
||||||
final Path dataDirectory = pantheonBase.resolve("data"); |
|
||||||
Files.createDirectories(dataDirectory); |
|
||||||
deleteDirectoryContents(dataDirectory, RecursiveDeleteOption.ALLOW_INSECURE); |
|
||||||
pantheonBin = pantheonBase.resolve("bin").resolve("pantheon"); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void startsWithoutArguments() throws Exception { |
|
||||||
final File stdout = temporaryFolder.newFile(); |
|
||||||
final File stderr = temporaryFolder.newFile(); |
|
||||||
final ProcessBuilder processBuilder = |
|
||||||
new ProcessBuilder(pantheonBin.toString()).redirectOutput(stdout).redirectError(stderr); |
|
||||||
processBuilder.environment().remove("JAVA_TOOL_OPTIONS"); |
|
||||||
final Process pantheon = processBuilder.start(); |
|
||||||
try { |
|
||||||
|
|
||||||
final OkHttpClient client = new OkHttpClient.Builder().build(); |
|
||||||
waitForPort(JsonRpcConfiguration.DEFAULT_JSON_RPC_PORT); |
|
||||||
|
|
||||||
try (Response jsonRpcResponse = |
|
||||||
client |
|
||||||
.newCall( |
|
||||||
new Request.Builder() |
|
||||||
.url("http://localhost:" + JsonRpcConfiguration.DEFAULT_JSON_RPC_PORT) |
|
||||||
.post( |
|
||||||
RequestBody.create( |
|
||||||
MediaType.parse("application/json; charset=utf-8"), |
|
||||||
"{\"jsonrpc\":\"2.0\",\"id\":" |
|
||||||
+ Json.encode(1) |
|
||||||
+ ",\"method\":\"web3_clientVersion\"}")) |
|
||||||
.build()) |
|
||||||
.execute()) { |
|
||||||
assertThat(jsonRpcResponse.code()).isEqualTo(HttpURLConnection.HTTP_OK); |
|
||||||
} |
|
||||||
|
|
||||||
pantheon.destroy(); |
|
||||||
assertThat(pantheon.waitFor(10L, TimeUnit.SECONDS)).isTrue(); |
|
||||||
// When JVM receives SIGTERM it exits 143
|
|
||||||
assertThat(pantheon.exitValue()).isEqualTo(143); |
|
||||||
|
|
||||||
} finally { |
|
||||||
pantheon.destroyForcibly(); |
|
||||||
pantheon.waitFor(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private static void waitForPort(final int port) { |
|
||||||
Awaitility.await() |
|
||||||
.ignoreExceptions() |
|
||||||
.until( |
|
||||||
() -> { |
|
||||||
try (Socket client = new Socket(InetAddress.getLoopbackAddress(), port)) { |
|
||||||
return true; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
@ -1,121 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.FileNotFoundException; |
|
||||||
import java.io.IOException; |
|
||||||
import java.net.URISyntaxException; |
|
||||||
import java.net.URL; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
import com.github.dockerjava.api.DockerClient; |
|
||||||
import com.github.dockerjava.api.model.BuildResponseItem; |
|
||||||
import com.github.dockerjava.core.command.BuildImageResultCallback; |
|
||||||
import com.google.common.io.Resources; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
|
|
||||||
public class DockerUtils { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates docker image |
|
||||||
* |
|
||||||
* @return docker image ID |
|
||||||
* @throws FileNotFoundException if the Dockerfile can not be located |
|
||||||
*/ |
|
||||||
public static String createPantheonDockerImage(final DockerClient dockerClient, final String name) |
|
||||||
throws FileNotFoundException { |
|
||||||
File dockerFile; |
|
||||||
try { |
|
||||||
final String resource = DockerUtils.class.getPackage().getName().replaceAll("\\.", "/"); |
|
||||||
final URL url = Resources.getResource(resource); |
|
||||||
if (url == null) throw new FileNotFoundException("Resource Not Found: " + resource); |
|
||||||
dockerFile = findParentDirBySiblingName(new File(url.toURI()), "gradlew.bat"); |
|
||||||
|
|
||||||
if (dockerFile == null) throw new FileNotFoundException("File Not Found: " + url); |
|
||||||
|
|
||||||
if (!dockerFile.exists()) throw new FileNotFoundException("File Not Found: " + dockerFile); |
|
||||||
} catch (final URISyntaxException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
|
|
||||||
String imageId; |
|
||||||
try (BuildImageResultCallback callback = |
|
||||||
new BuildImageResultCallback() { |
|
||||||
@Override |
|
||||||
public void onNext(final BuildResponseItem item) { |
|
||||||
LOG.info("createDockerImage log:" + item); |
|
||||||
super.onNext(item); |
|
||||||
} |
|
||||||
}) { |
|
||||||
|
|
||||||
final Set<String> tags = new HashSet<>(); |
|
||||||
if (name != null) { |
|
||||||
tags.add(name); |
|
||||||
} |
|
||||||
|
|
||||||
LOG.info("Creating Docker Image for : " + dockerFile); |
|
||||||
imageId = dockerClient.buildImageCmd(dockerFile).withTags(tags).exec(callback).awaitImageId(); |
|
||||||
LOG.info("Created Docker Image [" + imageId + "] for : " + dockerFile); |
|
||||||
} catch (final IOException e) { |
|
||||||
throw new RuntimeException("Failed to create Docker image for " + dockerFile, e); |
|
||||||
} |
|
||||||
return imageId; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates docker image |
|
||||||
* |
|
||||||
* @param imageType used in locating the correct Dockerfile on disk. eg "pantheon", "geth" |
|
||||||
* @return docker image ID |
|
||||||
* @throws FileNotFoundException if the Dockerfile can not be located |
|
||||||
*/ |
|
||||||
public static String createDockerImage( |
|
||||||
final DockerClient dockerClient, final String name, final String imageType) |
|
||||||
throws FileNotFoundException { |
|
||||||
File dockerFile; |
|
||||||
try { |
|
||||||
final String resource = |
|
||||||
DockerUtils.class.getPackage().getName().replaceAll("\\.", "/") |
|
||||||
+ "/docker/" |
|
||||||
+ imageType |
|
||||||
+ "/Dockerfile-" |
|
||||||
+ imageType; |
|
||||||
final URL url = Resources.getResource(resource); |
|
||||||
if (url == null) throw new FileNotFoundException("Resource Not Found: " + resource); |
|
||||||
dockerFile = new File(url.toURI()); |
|
||||||
if (!dockerFile.exists()) throw new FileNotFoundException("File Not Found: " + dockerFile); |
|
||||||
} catch (final URISyntaxException e) { |
|
||||||
throw new RuntimeException(e); |
|
||||||
} |
|
||||||
|
|
||||||
final BuildImageResultCallback callback = |
|
||||||
new BuildImageResultCallback() { |
|
||||||
@Override |
|
||||||
public void onNext(final BuildResponseItem item) { |
|
||||||
LOG.info("createDockerImage log:" + item); |
|
||||||
super.onNext(item); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
final Set<String> tags = new HashSet<>(); |
|
||||||
if (name != null) { |
|
||||||
tags.add(name); |
|
||||||
} |
|
||||||
|
|
||||||
return dockerClient.buildImageCmd(dockerFile).withTags(tags).exec(callback).awaitImageId(); |
|
||||||
} |
|
||||||
|
|
||||||
public static File findParentDirBySiblingName(final File thisFile, final String siblingName) { |
|
||||||
File parent = thisFile.getParentFile(); |
|
||||||
while (parent != null) { |
|
||||||
final File file = new File(parent.getAbsolutePath() + File.separatorChar + siblingName); |
|
||||||
if (file.exists()) { |
|
||||||
return parent; |
|
||||||
} |
|
||||||
parent = parent.getParentFile(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
} |
|
@ -1,65 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import static java.util.concurrent.TimeUnit.SECONDS; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.net.ConnectException; |
|
||||||
|
|
||||||
import io.vertx.core.json.Json; |
|
||||||
import io.vertx.core.json.JsonArray; |
|
||||||
import io.vertx.core.json.JsonObject; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
import org.awaitility.Awaitility; |
|
||||||
|
|
||||||
/** Helper class that performs common JSON-RPC Admin calls */ |
|
||||||
public class NodeAdminRpcUtils { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
public static JsonArray postMethodArray(final TestClusterNode node, final String method) |
|
||||||
throws IOException { |
|
||||||
if (node.isBootNode()) |
|
||||||
throw new IllegalArgumentException("Can't Call JSON-RPC on boot node. node=" + node); |
|
||||||
final String id = "123"; |
|
||||||
final String body = |
|
||||||
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"" + method + "\"}"; |
|
||||||
final JsonObject json = node.executeJsonRpc(null, "POST", body); |
|
||||||
return json.getJsonArray("result"); |
|
||||||
} |
|
||||||
|
|
||||||
public static String postMethodString(final TestClusterNode node, final String method) |
|
||||||
throws IOException { |
|
||||||
if (node.isBootNode()) |
|
||||||
throw new IllegalArgumentException("Can't Call JSON-RPC on boot node. node=" + node); |
|
||||||
final String id = "123"; |
|
||||||
final String body = |
|
||||||
"{\"jsonrpc\":\"2.0\",\"id\":" + Json.encode(id) + ",\"method\":\"" + method + "\"}"; |
|
||||||
final JsonObject json = node.executeJsonRpc(null, "POST", body); |
|
||||||
return json.getString("result"); |
|
||||||
} |
|
||||||
|
|
||||||
public static JsonArray getPeersJson(final TestClusterNode node) throws IOException { |
|
||||||
return postMethodArray(node, "admin_peers"); |
|
||||||
} |
|
||||||
|
|
||||||
/** Verify JSON-RPC is accessible. */ |
|
||||||
public static void testWeb3ClientVersionSuccessful( |
|
||||||
final TestClusterNode node, final String prefix) { |
|
||||||
Awaitility.await() |
|
||||||
.atMost(30, SECONDS) |
|
||||||
.ignoreException(ConnectException.class) |
|
||||||
.until( |
|
||||||
() -> { |
|
||||||
final String result = postMethodString(node, "web3_clientVersion"); |
|
||||||
return result.startsWith(prefix); |
|
||||||
}); |
|
||||||
} |
|
||||||
|
|
||||||
public static void testWeb3ClientVersionGeth(final TestClusterNode node) { |
|
||||||
testWeb3ClientVersionSuccessful(node, "Geth/"); |
|
||||||
} |
|
||||||
|
|
||||||
public static void testWeb3ClientVersionPantheon(final TestClusterNode node) { |
|
||||||
testWeb3ClientVersionSuccessful(node, "pantheon/"); |
|
||||||
} |
|
||||||
} |
|
@ -1,494 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import static java.lang.Thread.sleep; |
|
||||||
import static org.apache.commons.lang.StringUtils.join; |
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream; |
|
||||||
import java.io.Closeable; |
|
||||||
import java.io.File; |
|
||||||
import java.io.FileNotFoundException; |
|
||||||
import java.io.IOException; |
|
||||||
import java.net.InetSocketAddress; |
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.HashSet; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
import com.github.dockerjava.api.DockerClient; |
|
||||||
import com.github.dockerjava.api.command.CreateContainerCmd; |
|
||||||
import com.github.dockerjava.api.command.CreateContainerResponse; |
|
||||||
import com.github.dockerjava.api.command.ExecCreateCmdResponse; |
|
||||||
import com.github.dockerjava.api.command.InspectContainerResponse; |
|
||||||
import com.github.dockerjava.api.model.ExposedPort; |
|
||||||
import com.github.dockerjava.api.model.InternetProtocol; |
|
||||||
import com.github.dockerjava.api.model.Ports; |
|
||||||
import com.github.dockerjava.core.DefaultDockerClientConfig; |
|
||||||
import com.github.dockerjava.core.DockerClientBuilder; |
|
||||||
import com.github.dockerjava.core.command.ExecStartResultCallback; |
|
||||||
import org.apache.commons.io.FileUtils; |
|
||||||
import org.apache.commons.io.LineIterator; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
import org.assertj.core.api.Assertions; |
|
||||||
|
|
||||||
public final class TestCluster implements Closeable { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
private final DockerClient dockerClient; |
|
||||||
|
|
||||||
private final List<TestClusterNode> nodes = new ArrayList<>(); |
|
||||||
private final Map<String, String> imageIds = new HashMap<>(); |
|
||||||
private final List<String> bootNodes = new ArrayList<>(); |
|
||||||
|
|
||||||
private final String clusterPrefix; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param clusterPrefix Prefix to be used for all resources (eg data dirs, docker containers) used |
|
||||||
* by this cluster. This will make it easier to cleanup after test runs in the case of a |
|
||||||
* catastrophic failure where the test can not clean up after itself. Consider something like |
|
||||||
* "myTestSuiteName-datetime" |
|
||||||
*/ |
|
||||||
public TestCluster(final String clusterPrefix) { |
|
||||||
Assertions.assertThat(clusterPrefix).isNotNull(); |
|
||||||
this.clusterPrefix = clusterPrefix; |
|
||||||
dockerClient = |
|
||||||
DockerClientBuilder.getInstance( |
|
||||||
DefaultDockerClientConfig.createDefaultConfigBuilder().build()) |
|
||||||
.build(); |
|
||||||
} |
|
||||||
|
|
||||||
/** Returns an unmodifiable List of the cluster's nodes. */ |
|
||||||
public List<TestClusterNode> getNodes() { |
|
||||||
return Collections.unmodifiableList(nodes); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a Pantheon boot-node in a docker container for this cluster |
|
||||||
* |
|
||||||
* @throws FileNotFoundException if the Dockerfile can't be found |
|
||||||
*/ |
|
||||||
public TestClusterNode addPantheonBootDockerNode(final String containerName) |
|
||||||
throws FileNotFoundException { |
|
||||||
throw new UnsupportedOperationException("Pantheon Boot Notes are not yet supported"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a Pantheon full-node in a docker container for this cluster |
|
||||||
* |
|
||||||
* @throws FileNotFoundException if the Dockerfile can't be found |
|
||||||
*/ |
|
||||||
public TestClusterNode addPantheonFullDockerNode(final String containerName) |
|
||||||
throws FileNotFoundException { |
|
||||||
if (bootNodes.isEmpty()) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"Must result at least 1 boot node in this cluster before added regular nodes"); |
|
||||||
} |
|
||||||
return addPantheonDockerNode(false, containerName, null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a Pantheon Docker container with an optional custom start command. |
|
||||||
* |
|
||||||
* @param isBootNode true if this node is a boot-only node. |
|
||||||
* @param containerName name for container |
|
||||||
* @param cmd Optional. Command to override start the container with. NULL will use the default |
|
||||||
* from Dockerfile. One use is to be able to start both full-node and boot-node using the same |
|
||||||
* image |
|
||||||
*/ |
|
||||||
private TestClusterNode addPantheonDockerNode( |
|
||||||
final boolean isBootNode, final String containerName, final String cmd) |
|
||||||
throws FileNotFoundException { |
|
||||||
final String imageName = clusterPrefix + ":pantheon"; |
|
||||||
if (!imageIds.containsKey(imageName)) { |
|
||||||
// Only Create the image one time
|
|
||||||
final String imageId = DockerUtils.createPantheonDockerImage(dockerClient, imageName); |
|
||||||
imageIds.put(imageName, imageId); |
|
||||||
} |
|
||||||
|
|
||||||
final List<String> env = new ArrayList<>(); |
|
||||||
env.add("bootnodes=" + join(bootNodes, ',')); |
|
||||||
|
|
||||||
final String hostName = containerName; |
|
||||||
// TODO: Run as non-root user
|
|
||||||
final CreateContainerCmd createCtrCmd = |
|
||||||
dockerClient |
|
||||||
.createContainerCmd(imageName) |
|
||||||
.withName(containerName) |
|
||||||
.withPublishAllPorts(Boolean.TRUE) |
|
||||||
.withHostName(hostName) |
|
||||||
.withEnv(env) |
|
||||||
.withUser("root"); |
|
||||||
if (cmd != null) { |
|
||||||
// Override start command if one was provided
|
|
||||||
createCtrCmd.withCmd(cmd); |
|
||||||
} else { |
|
||||||
final List<String> args = new ArrayList<>(); |
|
||||||
args.add("--bootnodes"); |
|
||||||
args.add(join(bootNodes, ',')); |
|
||||||
args.add("--rpc-listen"); |
|
||||||
args.add("0.0.0.0:8545"); |
|
||||||
args.add("--genesis"); |
|
||||||
args.add("/opt/pantheon/genesis.json"); |
|
||||||
createCtrCmd.withCmd(args); |
|
||||||
} |
|
||||||
final CreateContainerResponse createCtrResp = createCtrCmd.exec(); |
|
||||||
final String containerId = createCtrResp.getId(); |
|
||||||
LOG.info( |
|
||||||
"Starting Container: " |
|
||||||
+ containerName |
|
||||||
+ ", id=" |
|
||||||
+ containerId |
|
||||||
+ ", cmd=" |
|
||||||
+ join(createCtrCmd.getCmd(), ' ')); |
|
||||||
dockerClient.startContainerCmd(containerId).exec(); |
|
||||||
|
|
||||||
final InspectContainerResponse startedContainer = |
|
||||||
dockerClient.inspectContainerCmd(containerId).exec(); |
|
||||||
|
|
||||||
final String ipAddress = startedContainer.getNetworkSettings().getIpAddress(); |
|
||||||
final Ports actualPorts = startedContainer.getNetworkSettings().getPorts(); |
|
||||||
|
|
||||||
Ports.Binding hostPort = actualPorts.getBindings().get(new ExposedPort(8545))[0]; |
|
||||||
final int jsonRpcPort = Integer.valueOf(hostPort.getHostPortSpec()); |
|
||||||
|
|
||||||
hostPort = actualPorts.getBindings().get(new ExposedPort(30303, InternetProtocol.UDP))[0]; |
|
||||||
final int discoveryPort = Integer.valueOf(hostPort.getHostPortSpec()); |
|
||||||
|
|
||||||
final String filePath = "/var/lib/pantheon/node01/enode.log"; |
|
||||||
// TODO: Rename getGethEnode, or make different method for pantheon
|
|
||||||
final String eNode = getGethEnode(dockerClient, containerId, filePath); |
|
||||||
|
|
||||||
LOG.info("eNode = " + eNode); |
|
||||||
final InetSocketAddress discoveryAddress = new InetSocketAddress(ipAddress, 30303); |
|
||||||
final InetSocketAddress jsonRpcAddress = new InetSocketAddress(ipAddress, 8545); |
|
||||||
final InetSocketAddress hostDiscoveryAddress = |
|
||||||
new InetSocketAddress("localhost", discoveryPort); |
|
||||||
final InetSocketAddress hostJsonRpcAddress = new InetSocketAddress("localhost", jsonRpcPort); |
|
||||||
final TestClusterNode node = |
|
||||||
new TestDockerNode( |
|
||||||
dockerClient, |
|
||||||
hostName, |
|
||||||
containerId, |
|
||||||
isBootNode, |
|
||||||
discoveryAddress, |
|
||||||
jsonRpcAddress, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
eNode); |
|
||||||
nodes.add(node); |
|
||||||
LOG.info(String.format("Added node : %s", node)); |
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a Geth boot-node in a docker container for this cluster |
|
||||||
* |
|
||||||
* @throws FileNotFoundException if the Dockerfile can't be found |
|
||||||
*/ |
|
||||||
public TestClusterNode addGethBootDockerNode(final String containerName) |
|
||||||
throws FileNotFoundException { |
|
||||||
// TODO: Figure out sh -c syntax so this node is started the same way full nodes are, and
|
|
||||||
// show up in the same way in ps list.
|
|
||||||
// TestClusterNode node = addGethDockerNode(containerName, "/bin/sh -c /runBootNode.sh");
|
|
||||||
final TestClusterNode node = addGethDockerNode(true, containerName, "/runBootNode.sh"); |
|
||||||
bootNodes.add(node.getEnode()); |
|
||||||
return node; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a Geth full-node in a docker container for this cluster |
|
||||||
* |
|
||||||
* @throws FileNotFoundException if the Dockerfile can't be found |
|
||||||
*/ |
|
||||||
public TestClusterNode addGethFullDockerNode(final String containerName) |
|
||||||
throws FileNotFoundException { |
|
||||||
if (bootNodes.isEmpty()) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"Must result at least 1 boot node in this cluster before added regular nodes"); |
|
||||||
} |
|
||||||
return addGethDockerNode(false, containerName, null); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Create a Geth Docker container with an optional custom start command. |
|
||||||
* |
|
||||||
* @param isBootNode true if this node is a boot-only node. |
|
||||||
* @param containerName name for container |
|
||||||
* @param cmd Optional. Command to override start the container with. NULL will use the default |
|
||||||
* from Dockerfile. One use is to be able to start both Geth full-node and boot-node using the |
|
||||||
* same image |
|
||||||
*/ |
|
||||||
private TestClusterNode addGethDockerNode( |
|
||||||
final boolean isBootNode, final String containerName, final String cmd) |
|
||||||
throws FileNotFoundException { |
|
||||||
final String imageName = clusterPrefix + ":geth"; |
|
||||||
if (!imageIds.containsKey(imageName)) { |
|
||||||
// Only Create the image one time
|
|
||||||
final String imageId = DockerUtils.createDockerImage(dockerClient, imageName, "geth"); |
|
||||||
imageIds.put(imageName, imageId); |
|
||||||
} |
|
||||||
|
|
||||||
final List<String> env = new ArrayList<>(); |
|
||||||
env.add("geth_bootnodes=" + join(bootNodes, ',')); |
|
||||||
|
|
||||||
final String hostName = containerName; |
|
||||||
// TODO: Run as non-root user
|
|
||||||
final CreateContainerCmd createCtrCmd = |
|
||||||
dockerClient |
|
||||||
.createContainerCmd(imageName) |
|
||||||
.withName(containerName) |
|
||||||
.withPublishAllPorts(Boolean.TRUE) |
|
||||||
.withHostName(hostName) |
|
||||||
.withEnv(env) |
|
||||||
.withUser("root"); |
|
||||||
if (cmd != null) { |
|
||||||
// Override start command if one was provided
|
|
||||||
createCtrCmd.withCmd(cmd); |
|
||||||
} else { |
|
||||||
final List<String> args = new ArrayList<>(); |
|
||||||
args.add("--networkid"); |
|
||||||
args.add("15"); // Test use networkid 15 so there is no chance of connecting to MainNet
|
|
||||||
createCtrCmd.withCmd(args); |
|
||||||
} |
|
||||||
final CreateContainerResponse createCtrResp = createCtrCmd.exec(); |
|
||||||
final String containerId = createCtrResp.getId(); |
|
||||||
LOG.info("Starting Container: " + containerName + ", id=" + containerId); |
|
||||||
dockerClient.startContainerCmd(containerId).exec(); |
|
||||||
|
|
||||||
final InspectContainerResponse startedContainer = |
|
||||||
dockerClient.inspectContainerCmd(containerId).exec(); |
|
||||||
|
|
||||||
final String ipAddress = startedContainer.getNetworkSettings().getIpAddress(); |
|
||||||
final Ports actualPorts = startedContainer.getNetworkSettings().getPorts(); |
|
||||||
|
|
||||||
Ports.Binding hostPort = actualPorts.getBindings().get(new ExposedPort(8545))[0]; |
|
||||||
final int jsonRpcPort = Integer.valueOf(hostPort.getHostPortSpec()); |
|
||||||
|
|
||||||
hostPort = actualPorts.getBindings().get(new ExposedPort(30303, InternetProtocol.UDP))[0]; |
|
||||||
final int discoveryPort = Integer.valueOf(hostPort.getHostPortSpec()); |
|
||||||
|
|
||||||
final String filePath = "/var/lib/geth/node01/enode.log"; |
|
||||||
final String eNode = getGethEnode(dockerClient, containerId, filePath); |
|
||||||
|
|
||||||
LOG.info("eNode = " + eNode); |
|
||||||
final InetSocketAddress discoveryAddress = new InetSocketAddress(ipAddress, 30303); |
|
||||||
final InetSocketAddress jsonRpcAddress = new InetSocketAddress(ipAddress, 8545); |
|
||||||
final InetSocketAddress hostDiscoveryAddress = |
|
||||||
new InetSocketAddress("localhost", discoveryPort); |
|
||||||
final InetSocketAddress hostJsonRpcAddress = new InetSocketAddress("localhost", jsonRpcPort); |
|
||||||
final TestClusterNode gethNode = |
|
||||||
new TestDockerNode( |
|
||||||
dockerClient, |
|
||||||
hostName, |
|
||||||
containerId, |
|
||||||
isBootNode, |
|
||||||
discoveryAddress, |
|
||||||
jsonRpcAddress, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
eNode); |
|
||||||
nodes.add(gethNode); |
|
||||||
LOG.info(String.format("Added node : %s", gethNode)); |
|
||||||
return gethNode; |
|
||||||
} |
|
||||||
|
|
||||||
public static String getGethEnode( |
|
||||||
final DockerClient dockerClient, final String containerId, final String filePath) { |
|
||||||
final ByteArrayOutputStream stdout = new ByteArrayOutputStream(); |
|
||||||
final ByteArrayOutputStream stderr = new ByteArrayOutputStream(); |
|
||||||
try { |
|
||||||
// Todo, Poll instead of long sleep
|
|
||||||
sleep(5000); |
|
||||||
final ExecCreateCmdResponse execCreateCmdResponse = |
|
||||||
dockerClient |
|
||||||
.execCreateCmd(containerId) |
|
||||||
.withAttachStdout(true) |
|
||||||
.withAttachStderr(true) |
|
||||||
.withCmd("/bin/cat", filePath) |
|
||||||
.exec(); |
|
||||||
dockerClient |
|
||||||
.execStartCmd(execCreateCmdResponse.getId()) |
|
||||||
.exec(new ExecStartResultCallback(stdout, stderr)) |
|
||||||
.awaitCompletion(); |
|
||||||
} catch (final InterruptedException e) { |
|
||||||
throw new RuntimeException("Unable to get Geth Enode.", e); |
|
||||||
} |
|
||||||
|
|
||||||
// Todo Validate that output is valid enode format
|
|
||||||
// Todo validate stderr is empty
|
|
||||||
return stdout.toString().trim(); |
|
||||||
} |
|
||||||
|
|
||||||
public TestClusterNode addGethLocalNode(final String gethCmd, final String nodeNum) |
|
||||||
throws IOException { |
|
||||||
final SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd-HHmmss"); |
|
||||||
|
|
||||||
final String imageName = "pantheontest-" + fmt.format(new Date()) + ":geth"; |
|
||||||
final String hostName = "localhost"; |
|
||||||
final String tmpPath = System.getProperty("java.io.tmpdir"); |
|
||||||
if (tmpPath == null) |
|
||||||
throw new IllegalStateException("System Property 'java.io.tmpdir' must not be null"); |
|
||||||
final File datadir = new File(tmpPath + "/" + imageName); |
|
||||||
datadir.mkdirs(); |
|
||||||
final int ethPort = Integer.parseInt("304" + nodeNum); |
|
||||||
final int jsonRpcPort = Integer.parseInt("85" + nodeNum); |
|
||||||
final int discoveryPort = ethPort; |
|
||||||
|
|
||||||
final InetSocketAddress hostDiscoveryAddress = new InetSocketAddress(hostName, ethPort); |
|
||||||
final InetSocketAddress hostJsonRpcAddress = new InetSocketAddress(hostName, jsonRpcPort); |
|
||||||
|
|
||||||
final List<String> cmdList = new ArrayList<>(); |
|
||||||
cmdList.add(gethCmd); |
|
||||||
cmdList.add("--datadir"); |
|
||||||
cmdList.add(datadir.getAbsolutePath()); |
|
||||||
cmdList.add("--port"); |
|
||||||
cmdList.add(String.valueOf(ethPort)); |
|
||||||
cmdList.add("--bootNodes"); |
|
||||||
cmdList.add(join(bootNodes, ',')); |
|
||||||
cmdList.add("--rpc"); |
|
||||||
cmdList.add("--rpcapi"); |
|
||||||
cmdList.add("eth,web3,admin"); |
|
||||||
cmdList.add("--rpcaddr"); |
|
||||||
cmdList.add("0.0.0.0"); |
|
||||||
cmdList.add("--rpcport"); |
|
||||||
cmdList.add(String.valueOf(jsonRpcPort)); |
|
||||||
cmdList.add("rpc"); |
|
||||||
|
|
||||||
final File log = new File(datadir, "geth.log"); |
|
||||||
final ProcessBuilder pb = |
|
||||||
new ProcessBuilder(gethCmd) |
|
||||||
.directory(datadir) |
|
||||||
.redirectErrorStream(true) |
|
||||||
.redirectOutput(ProcessBuilder.Redirect.appendTo(log)); |
|
||||||
|
|
||||||
LOG.info("CmdList: " + join(cmdList, ' ')); |
|
||||||
final Process p = pb.start(); |
|
||||||
|
|
||||||
Assertions.assertThat(pb.redirectInput()).isEqualTo(ProcessBuilder.Redirect.PIPE); |
|
||||||
Assertions.assertThat(pb.redirectOutput().file()).isEqualTo(log); |
|
||||||
Assertions.assertThat(p.getInputStream().read()).isEqualTo(-1); |
|
||||||
|
|
||||||
final TestClusterNode gethNode = |
|
||||||
new TestGethLocalNode( |
|
||||||
datadir, |
|
||||||
imageName, |
|
||||||
false, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
getEnodeFromLog(log)); |
|
||||||
nodes.add(gethNode); |
|
||||||
LOG.info(String.format("Added node : %s", gethNode)); |
|
||||||
return gethNode; |
|
||||||
} |
|
||||||
|
|
||||||
public String getEnodeFromLog(final File file) throws IOException { |
|
||||||
return "enode://578e065716636c51c6d4b991c8299d920c8def1957e5fb2dc1c81d3ccf99a072bdcddad86e081e7f7d085a4bc4dbc2e04fe38c90cba810cee50af751e5e3ac70@192.168.71.128:30301"; |
|
||||||
// return grepFile(file, "UDP listener up *self=").iterator().next();
|
|
||||||
} |
|
||||||
|
|
||||||
public Collection<String> grepFile(final File file, final String regex) throws IOException { |
|
||||||
final Set<String> results = new HashSet<>(); |
|
||||||
final LineIterator it = FileUtils.lineIterator(file, "UTF-8"); |
|
||||||
try { |
|
||||||
while (it.hasNext()) { |
|
||||||
final String line = it.nextLine(); |
|
||||||
if (line.matches(regex)) { |
|
||||||
results.add(line); |
|
||||||
} |
|
||||||
} |
|
||||||
} finally { |
|
||||||
LineIterator.closeQuietly(it); |
|
||||||
} |
|
||||||
return results; |
|
||||||
} |
|
||||||
|
|
||||||
public TestClusterNode addParityNode() { |
|
||||||
if (bootNodes.isEmpty()) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"Must result at least 1 boot node in this cluster before added regular nodes"); |
|
||||||
} |
|
||||||
// TODO: Implement Parity Container Support
|
|
||||||
throw new UnsupportedOperationException("Add ParityNode is not yet supported"); |
|
||||||
} |
|
||||||
|
|
||||||
public TestClusterNode addCppEthNode() { |
|
||||||
if (bootNodes.isEmpty()) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"Must result at least 1 boot node in this cluster before added regular nodes"); |
|
||||||
} |
|
||||||
// TODO: Implement CppEth Container Support
|
|
||||||
throw new UnsupportedOperationException("Add CppEthNode is not yet supported"); |
|
||||||
} |
|
||||||
|
|
||||||
public TestClusterNode addPantheonNode() { |
|
||||||
if (bootNodes.isEmpty()) { |
|
||||||
throw new IllegalStateException( |
|
||||||
"Must result at least 1 boot node in this cluster before added regular nodes"); |
|
||||||
} |
|
||||||
// TODO: Implement Pantheon Container Support
|
|
||||||
throw new UnsupportedOperationException("Add PantheonNode is not yet supported"); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void close() throws IOException { |
|
||||||
// TODO: If test times are too long, consider creating/destroying nodes in parallel
|
|
||||||
Exception exToThrow = null; |
|
||||||
for (final Iterator<TestClusterNode> it = nodes.iterator(); it.hasNext(); ) { |
|
||||||
final TestClusterNode node = it.next(); |
|
||||||
try { |
|
||||||
node.stop(); |
|
||||||
} catch (final Exception e) { |
|
||||||
if (exToThrow == null) exToThrow = e; |
|
||||||
LOG.error("Error Stopping node. continuing with close(). node = " + node, e); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
node.delete(); |
|
||||||
it.remove(); // Remove from our list of nodes only if it was successfully removed.
|
|
||||||
} catch (final Exception e) { |
|
||||||
if (exToThrow == null) exToThrow = e; |
|
||||||
LOG.error("Error deleting node. continuing with close(). node = " + node, e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (final Iterator<String> it = imageIds.keySet().iterator(); it.hasNext(); ) { |
|
||||||
final String imageId = it.next(); |
|
||||||
try { |
|
||||||
dockerClient.removeImageCmd(imageId).exec(); |
|
||||||
it.remove(); |
|
||||||
} catch (final Exception e) { |
|
||||||
if (exToThrow == null) exToThrow = e; |
|
||||||
LOG.error("Error removing docker image [" + imageId + "]. continuing with close()", e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
dockerClient.close(); |
|
||||||
} catch (final IOException e) { |
|
||||||
if (exToThrow == null) exToThrow = e; |
|
||||||
LOG.warn("Error closing dockerClient. continuing with close()", e); |
|
||||||
} |
|
||||||
|
|
||||||
if (exToThrow != null) { |
|
||||||
throw new IOException("Error cleaning up cluster.", exToThrow); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
final StringBuilder sb = new StringBuilder("TestCluster{"); |
|
||||||
sb.append(", nodes=\n").append(join(nodes, "\n")); |
|
||||||
sb.append("\nimageIds=").append(imageIds); |
|
||||||
sb.append('}'); |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,177 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.math.BigInteger; |
|
||||||
import java.net.InetSocketAddress; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects; |
|
||||||
import io.vertx.core.json.JsonObject; |
|
||||||
import okhttp3.MediaType; |
|
||||||
import okhttp3.OkHttpClient; |
|
||||||
import okhttp3.Request; |
|
||||||
import okhttp3.RequestBody; |
|
||||||
import okhttp3.Response; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
import org.assertj.core.api.Assertions; |
|
||||||
|
|
||||||
public abstract class TestClusterNode { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); |
|
||||||
|
|
||||||
protected final String nodeName; |
|
||||||
protected final boolean isBootNode; |
|
||||||
protected final InetSocketAddress discoveryAddress; |
|
||||||
protected final InetSocketAddress jsonRpcAddress; |
|
||||||
protected final InetSocketAddress hostDiscoveryAddress; |
|
||||||
protected final InetSocketAddress hostJsonRpcAddress; |
|
||||||
protected final String enode; |
|
||||||
|
|
||||||
public TestClusterNode( |
|
||||||
final String nodeName, |
|
||||||
final boolean isBootNode, |
|
||||||
final InetSocketAddress discoveryAddress, |
|
||||||
final InetSocketAddress jsonRpcAddress, |
|
||||||
final InetSocketAddress hostDiscoveryAddress, |
|
||||||
final InetSocketAddress hostJsonRpcAddress, |
|
||||||
final String enode) { |
|
||||||
Assertions.assertThat(enode).isNotNull(); |
|
||||||
this.nodeName = nodeName; |
|
||||||
this.isBootNode = isBootNode; |
|
||||||
this.discoveryAddress = discoveryAddress; |
|
||||||
this.jsonRpcAddress = jsonRpcAddress; |
|
||||||
this.hostDiscoveryAddress = hostDiscoveryAddress; |
|
||||||
this.hostJsonRpcAddress = hostJsonRpcAddress; |
|
||||||
this.enode = enode; |
|
||||||
} |
|
||||||
|
|
||||||
public String getNodeName() { |
|
||||||
return nodeName; |
|
||||||
} |
|
||||||
|
|
||||||
public boolean isBootNode() { |
|
||||||
return isBootNode; |
|
||||||
} |
|
||||||
|
|
||||||
public InetSocketAddress getDiscoveryAddress() { |
|
||||||
return discoveryAddress; |
|
||||||
} |
|
||||||
|
|
||||||
public InetSocketAddress getJsonRpcAddress() { |
|
||||||
return jsonRpcAddress; |
|
||||||
} |
|
||||||
|
|
||||||
public InetSocketAddress getHostDiscoveryAddress() { |
|
||||||
return hostDiscoveryAddress; |
|
||||||
} |
|
||||||
|
|
||||||
public InetSocketAddress getHostJsonRpcAddress() { |
|
||||||
return hostJsonRpcAddress; |
|
||||||
} |
|
||||||
|
|
||||||
public String getEnode() { |
|
||||||
return enode; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* TODO: JSON WIZARDS! I bet there is a better way to do this. Pro Tips? TODO: JSON WIZARDS! |
|
||||||
* Should we have a JSON help lib for this stuff? or do we already have one? |
|
||||||
* |
|
||||||
* <p>Execute JsonRpc method against this node. Assumptions: - body is well formed. - HTTP |
|
||||||
* Response code is 200. Exception is thrown on any other response code - HTTP Response is valid |
|
||||||
* JSON-RPC value |
|
||||||
* |
|
||||||
* @param method HTTP Method. eg GET POST |
|
||||||
* @return HTTP Response Body as {@link JsonObject} |
|
||||||
*/ |
|
||||||
public JsonObject executeJsonRpc(final String path, final String method, final String body) |
|
||||||
throws IOException { |
|
||||||
final OkHttpClient client = new OkHttpClient(); |
|
||||||
|
|
||||||
// TODO: Should this be an incremented or random number?
|
|
||||||
final String id = "123"; |
|
||||||
final RequestBody reqBody = RequestBody.create(JSON, body); |
|
||||||
|
|
||||||
String myPath = (path != null) ? path : ""; |
|
||||||
if (!myPath.startsWith("/")) myPath = "/" + myPath; |
|
||||||
|
|
||||||
final String baseUrl = |
|
||||||
"http://" |
|
||||||
+ getJsonRpcAddress().getHostName() |
|
||||||
+ ":" |
|
||||||
+ getJsonRpcAddress().getPort() |
|
||||||
+ myPath; |
|
||||||
final Request request = new Request.Builder().method(method, reqBody).url(baseUrl).build(); |
|
||||||
LOG.debug("request:" + request); |
|
||||||
try (Response resp = client.newCall(request).execute()) { |
|
||||||
LOG.debug("response head: {}", resp); |
|
||||||
assertThat(resp.code()) |
|
||||||
.describedAs("Error processing request\nrequest=[%s]\nesponse=[%s]", request, resp) |
|
||||||
.isEqualTo(200); |
|
||||||
// Check general format of result
|
|
||||||
assertThat(resp.body()) |
|
||||||
.describedAs("Error processing request\nrequest=[%s]\nesponse=[%s]", request, resp) |
|
||||||
.isNotNull(); |
|
||||||
final JsonObject json = new JsonObject(resp.body().string()); |
|
||||||
// TODO: assertNoErrors
|
|
||||||
assertValidJsonRpcResult(json, id); |
|
||||||
LOG.debug("response body: {}", json); |
|
||||||
return json; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** JSON helper method */ |
|
||||||
protected static void assertValidJsonRpcResult(final JsonObject json, final Object id) { |
|
||||||
// Check all expected fieldnames are set
|
|
||||||
final Set<String> fieldNames = json.fieldNames(); |
|
||||||
assertThat(fieldNames.size()).isEqualTo(3); |
|
||||||
assertThat(fieldNames.contains("id")).isTrue(); |
|
||||||
assertThat(fieldNames.contains("jsonrpc")).isTrue(); |
|
||||||
assertThat(fieldNames.contains("result")).isTrue(); |
|
||||||
|
|
||||||
// Check standard field values
|
|
||||||
assertIdMatches(json, id); |
|
||||||
assertThat(json.getString("jsonrpc")).isEqualTo("2.0"); |
|
||||||
} |
|
||||||
|
|
||||||
/** JSON helper method */ |
|
||||||
protected static void assertIdMatches(final JsonObject json, final Object expectedId) { |
|
||||||
final Object actualId = json.getValue("id"); |
|
||||||
if (expectedId == null) { |
|
||||||
assertThat(actualId).isNull(); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
assertThat(expectedId) |
|
||||||
.isInstanceOfAny( |
|
||||||
String.class, Integer.class, Long.class, Float.class, Double.class, BigInteger.class); |
|
||||||
assertThat(actualId).isInstanceOf(expectedId.getClass()); |
|
||||||
assertThat(actualId.toString()).isEqualTo(expectedId.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
/** Start the node */ |
|
||||||
public abstract void start(); |
|
||||||
|
|
||||||
/** Stop the node */ |
|
||||||
public abstract void stop(); |
|
||||||
|
|
||||||
/** Delete the node and all related data from disk */ |
|
||||||
public abstract void delete(); |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return MoreObjects.toStringHelper(this) |
|
||||||
.add("nodeName", nodeName) |
|
||||||
.add("isBootNode", isBootNode) |
|
||||||
.add("discoveryAddress", discoveryAddress) |
|
||||||
.add("jsonRpcAddress", jsonRpcAddress) |
|
||||||
.add("hostDiscoveryAddress", hostDiscoveryAddress) |
|
||||||
.add("hostJsonRpcAddress", hostJsonRpcAddress) |
|
||||||
.add("enode", enode) |
|
||||||
.toString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,74 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import java.net.InetSocketAddress; |
|
||||||
|
|
||||||
import com.github.dockerjava.api.DockerClient; |
|
||||||
import com.google.common.base.MoreObjects; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
|
|
||||||
public class TestDockerNode extends TestClusterNode { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
protected String containerId; |
|
||||||
protected DockerClient dockerClient; |
|
||||||
|
|
||||||
public TestDockerNode( |
|
||||||
final DockerClient dockerClient, |
|
||||||
final String nodeName, |
|
||||||
final String containerId, |
|
||||||
final boolean isBootNode, |
|
||||||
final InetSocketAddress discoveryAddress, |
|
||||||
final InetSocketAddress jsonRpcAddress, |
|
||||||
final InetSocketAddress hostDiscoveryAddress, |
|
||||||
final InetSocketAddress hostJsonRpcAddress, |
|
||||||
final String enode) { |
|
||||||
super( |
|
||||||
nodeName, |
|
||||||
isBootNode, |
|
||||||
discoveryAddress, |
|
||||||
jsonRpcAddress, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
enode); |
|
||||||
this.containerId = containerId; |
|
||||||
this.dockerClient = dockerClient; |
|
||||||
} |
|
||||||
|
|
||||||
public String getContainerId() { |
|
||||||
return containerId; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return MoreObjects.toStringHelper(this) |
|
||||||
.add("nodeName", nodeName) |
|
||||||
.add("isBootNode", isBootNode) |
|
||||||
.add("discoveryAddress", discoveryAddress) |
|
||||||
.add("jsonRpcAddress", jsonRpcAddress) |
|
||||||
.add("hostDiscoveryAddress", hostDiscoveryAddress) |
|
||||||
.add("hostJsonRpcAddress", hostJsonRpcAddress) |
|
||||||
.add("enode", enode) |
|
||||||
.add("containerId", containerId) |
|
||||||
.add("dockerClient", dockerClient) |
|
||||||
.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void start() { |
|
||||||
LOG.info("Calling stop on node {}", this); |
|
||||||
dockerClient.startContainerCmd(containerId).exec(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void stop() { |
|
||||||
LOG.info("Calling stop on node {}", this); |
|
||||||
dockerClient.stopContainerCmd(containerId).exec(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void delete() { |
|
||||||
LOG.info("Calling delete on node {}", this); |
|
||||||
dockerClient.removeContainerCmd(containerId).withForce(true).exec(); |
|
||||||
} |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
package net.consensys.pantheon.tests.cluster; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.net.InetSocketAddress; |
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects; |
|
||||||
import org.apache.logging.log4j.LogManager; |
|
||||||
import org.apache.logging.log4j.Logger; |
|
||||||
|
|
||||||
public class TestGethLocalNode extends TestClusterNode { |
|
||||||
private static final Logger LOG = LogManager.getLogger(); |
|
||||||
|
|
||||||
protected File dataDir; |
|
||||||
|
|
||||||
public TestGethLocalNode( |
|
||||||
final File dataDir, |
|
||||||
final String nodeName, |
|
||||||
final boolean isBootNode, |
|
||||||
final InetSocketAddress discoveryAddress, |
|
||||||
final InetSocketAddress jsonRpcAddress, |
|
||||||
final InetSocketAddress hostDiscoveryAddress, |
|
||||||
final InetSocketAddress hostJsonRpcAddress, |
|
||||||
final String enode) { |
|
||||||
super( |
|
||||||
nodeName, |
|
||||||
isBootNode, |
|
||||||
discoveryAddress, |
|
||||||
jsonRpcAddress, |
|
||||||
hostDiscoveryAddress, |
|
||||||
hostJsonRpcAddress, |
|
||||||
enode); |
|
||||||
this.dataDir = dataDir; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void start() { |
|
||||||
// TODO: Implement Start()
|
|
||||||
LOG.warn("TODO: Implement Start()"); |
|
||||||
// LOG.info("Calling stop on node {}", this);
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void stop() { |
|
||||||
// TODO: Implement Stop()
|
|
||||||
LOG.warn("TODO: Implement Stop()"); |
|
||||||
// LOG.info("Calling stop on node {}", this);
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void delete() { |
|
||||||
// TODO: Implement Delete()
|
|
||||||
LOG.warn("TODO: Implement DELETE()"); |
|
||||||
// LOG.info("Calling delete on node {}", this);
|
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
return MoreObjects.toStringHelper(this) |
|
||||||
.add("nodeName", nodeName) |
|
||||||
.add("isBootNode", isBootNode) |
|
||||||
.add("discoveryAddress", discoveryAddress) |
|
||||||
.add("jsonRpcAddress", jsonRpcAddress) |
|
||||||
.add("hostDiscoveryAddress", hostDiscoveryAddress) |
|
||||||
.add("hostJsonRpcAddress", hostJsonRpcAddress) |
|
||||||
.add("enode", enode) |
|
||||||
.add("dataDir", dataDir) |
|
||||||
.toString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,25 +0,0 @@ |
|||||||
FROM ethereum/client-go:alltools-stable |
|
||||||
|
|
||||||
ENV NODE_NAME=node01 |
|
||||||
ENV DATA_DIR=/var/lib/geth/$NODE_NAME |
|
||||||
|
|
||||||
ENV HOME=/root |
|
||||||
|
|
||||||
RUN mkdir -p $DATA_DIR |
|
||||||
|
|
||||||
ADD genesis.json $DATA_DIR/genesis.json |
|
||||||
ADD gethUtils.sh /gethUtils.sh |
|
||||||
ADD run.sh /run.sh |
|
||||||
ADD runBootNode.sh /runBootNode.sh |
|
||||||
|
|
||||||
|
|
||||||
RUN echo "if [ -f '/gethUtils.sh' ]; then echo 'Sourcing /gethUtils.sh'; source /gethUtils.sh; fi\n" >> $HOME/.bashrc |
|
||||||
RUN sed -i s@REPLACE_NODE_NAME@$NODE_NAME@ /gethUtils.sh |
|
||||||
RUN sed -i s@REPLACE_DATA_DIR@$DATA_DIR@ /gethUtils.sh |
|
||||||
|
|
||||||
WORKDIR $HOME/ |
|
||||||
|
|
||||||
ENTRYPOINT ["/run.sh"] |
|
||||||
|
|
||||||
# List Exposed Ports |
|
||||||
EXPOSE 8084 8545 30303 30303/udp |
|
@ -1,45 +0,0 @@ |
|||||||
FROM ubuntu:18.04 |
|
||||||
|
|
||||||
ENV PATH /go-ethereum/build/bin:$PATH |
|
||||||
|
|
||||||
RUN useradd --create-home --user-group -u 999 appuser |
|
||||||
|
|
||||||
RUN apt-get update |
|
||||||
RUN apt-get install -y build-essential golang git net-tools iputils-ping netcat curl |
|
||||||
RUN apt-get install -y vim emacs |
|
||||||
|
|
||||||
WORKDIR / |
|
||||||
RUN git clone https://github.com/ethereum/go-ethereum |
|
||||||
# && git checkout tags/v1.8.7 |
|
||||||
WORKDIR /go-ethereum |
|
||||||
RUN make all |
|
||||||
|
|
||||||
RUN mkdir -p /ethereum/data/geth |
|
||||||
|
|
||||||
ADD genesis.json /ethereum/genesis.json |
|
||||||
ADD gethUtils.sh /gethUtils.sh |
|
||||||
ADD run.sh /run.sh |
|
||||||
ADD runBootNode.sh /runBootNode.sh |
|
||||||
ADD bash_aliases /home/appuser/.bash_aliases |
|
||||||
|
|
||||||
RUN chmod +x /run.sh /runBootNode.sh /gethUtils.sh /home/appuser/.bash_aliases |
|
||||||
RUN chown appuser:appuser /run.sh /runBootNode.sh /gethUtils.sh /home/appuser/.bash_aliases |
|
||||||
|
|
||||||
# store cmd to ~/.bash_history every time the prompt is displayed, instead of waiting for a clean exit from the shell |
|
||||||
RUN echo "export PROMPT_COMMAND=\"history -a\"" >> /root/.profile |
|
||||||
RUN cp /root/.profile /home/appuser/ |
|
||||||
RUN cp /root/.bashrc /home/appuser/ |
|
||||||
|
|
||||||
#RUN echo "if [ -f \"~/.bash_aliases\" ]; then echo 'Sourcing \"~/.bash_aliases\"'; source \"~/.bash_aliases\"; fi\n" >> /home/appuser/.bashrc |
|
||||||
RUN echo "if [ -f '/gethUtils.sh' ]; then echo 'Sourcing /gethUtils.sh'; source /gethUtils.sh; fi\n" >> /home/appuser/.bashrc |
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /go-ethereum |
|
||||||
RUN chown -R appuser:appuser /ethereum |
|
||||||
RUN chown -R appuser:appuser /go-ethereum |
|
||||||
|
|
||||||
USER appuser |
|
||||||
CMD /run.sh |
|
||||||
|
|
||||||
# List Exposed Ports |
|
||||||
EXPOSE 8084 8545 30303 30303/udp |
|
@ -1 +0,0 @@ |
|||||||
#!/bin/bash |
|
@ -1,25 +0,0 @@ |
|||||||
{ |
|
||||||
"config": { |
|
||||||
"chainId": 15, |
|
||||||
"homesteadBlock": 0, |
|
||||||
"eip155Block": 0, |
|
||||||
"eip158Block": 0, |
|
||||||
"ethash": { |
|
||||||
|
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
"alloc" : { |
|
||||||
"0x0000000000000000000000000000000000000001": {"balance": "111111111"}, |
|
||||||
"0x0000000000000000000000000000000000000002": {"balance": "222222222"} |
|
||||||
}, |
|
||||||
|
|
||||||
"coinbase" : "0x0000000000000000000000000000000000000000", |
|
||||||
"difficulty" : "0x0000001", |
|
||||||
"extraData" : "", |
|
||||||
"gasLimit" : "0x2fefd8", |
|
||||||
"nonce" : "0x0000000000000107", |
|
||||||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000", |
|
||||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000", |
|
||||||
"timestamp" : "0x00" |
|
||||||
} |
|
@ -1,42 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
|
|
||||||
function waitForLogLine() { |
|
||||||
# Note, this function will wait forever |
|
||||||
local myStr=$1 |
|
||||||
local myFile=$2 |
|
||||||
until grep -q "${myStr}" "${myFile}" |
|
||||||
do |
|
||||||
# echo "Sleeping 0.1s" |
|
||||||
sleep 0.1s |
|
||||||
done |
|
||||||
} |
|
||||||
|
|
||||||
function logEnode() { |
|
||||||
waitForLogLine 'UDP listener up *self=' $datadir/geth.log |
|
||||||
# echo "ip_addr=\$(getent hosts boot | awk '{ print \$1 }')" |
|
||||||
ip_addr=$(hostname -i) |
|
||||||
# ip_addr="192.168.71.128" |
|
||||||
echo "ip_addr=$ip_addr" |
|
||||||
|
|
||||||
echo "enode=\$( grep enode \$datadir/geth.log | tail -n 1 | sed s/^.*enode:/enode:/ | sed \"s/\[\:\:\]/$ip_addr/g\" )" |
|
||||||
enode=$( grep enode $datadir/geth.log | tail -n 1 | sed s/^.*enode:/enode:/ | sed "s/\[\:\:\]/$ip_addr/g" ) |
|
||||||
echo "enode=$enode" |
|
||||||
|
|
||||||
echo $enode > $BOOTENODEFILE |
|
||||||
echo cat file |
|
||||||
cat $BOOTENODEFILE |
|
||||||
} |
|
||||||
|
|
||||||
function sleepforever() { |
|
||||||
while true; do |
|
||||||
sleep 9999d |
|
||||||
done |
|
||||||
} |
|
||||||
|
|
||||||
datadir=REPLACE_DATA_DIR |
|
||||||
BOOTENODEFILE=$datadir/enode.log |
|
||||||
|
|
||||||
# Note: aliases dependent on $nodedir need to be loaded here instead of ~/.bash_aliases |
|
||||||
# because ~/.bash_aliases is loaded before this script is sourced. |
|
||||||
alias geth="geth --datadir=$datadir " |
|
||||||
alias peers="geth attach --exec 'admin.peers'" |
|
@ -1,11 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
|
|
||||||
source /gethUtils.sh |
|
||||||
|
|
||||||
cd /go-ethereum |
|
||||||
geth --datadir=$datadir init $datadir/genesis.json |
|
||||||
geth -verbosity 6 --datadir=$datadir --syncmode "full" --rpc --rpcapi eth,web3,admin --rpcaddr 0.0.0.0 --bootnodes="$geth_bootnodes" --networkid 15 &> $datadir/geth.log & |
|
||||||
|
|
||||||
logEnode |
|
||||||
|
|
||||||
sleepforever |
|
@ -1,13 +0,0 @@ |
|||||||
#!/bin/sh |
|
||||||
echo HI! |
|
||||||
|
|
||||||
source /gethUtils.sh |
|
||||||
|
|
||||||
BOOTNODE_CMD=bootnode |
|
||||||
|
|
||||||
$BOOTNODE_CMD --genkey=$nodedir/boot.key |
|
||||||
$BOOTNODE_CMD --nodekey=$nodedir/boot.key --addr=:30303 &> $datadir/geth.log & |
|
||||||
|
|
||||||
logEnode |
|
||||||
|
|
||||||
sleepforever |
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue