Skip to content

Commit

Permalink
inital implementation of native provider (#66)
Browse files Browse the repository at this point in the history
* inital imple of native provider

* fix logs assertions for native provider

* add native provider

* fix endpoint connection
  • Loading branch information
pepoviola authored Jan 17, 2022
1 parent ddc2ada commit 92f2a68
Show file tree
Hide file tree
Showing 18 changed files with 681 additions and 77 deletions.
2 changes: 1 addition & 1 deletion scripts/zombie-wrapper.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

# add /cfg as first `looking dir` to allow to overrides commands.
export PATH="/cfg":$PATH
export PATH="{{REMOTE_DIR}}":$PATH

# setup pipe
pipe=/tmp/zombiepipe
Expand Down
17 changes: 9 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,19 @@ process.on("unhandledRejection", async (err) => {
});

// Handle ctrl+c to trigger `exit`.
let alreadyTry = false;
process.on("SIGINT", async function () {
if (network) {
debug("removing namespace: " + network.namespace);
if (network && !alreadyTry) {
alreadyTry = true;
debug("Ctrl+c ... removing namespace: " + network.namespace);
await network.stop();
}
process.exit(2);
});

process.on("exit", async function () {
if (network) {
if (network && !alreadyTry) {
alreadyTry = true;
debug("removing namespace: " + network.namespace);
await network.uploadLogs();
await network.stop();
Expand All @@ -66,20 +69,18 @@ process.on("exit", async function () {
});

program
.addOption(
new Option("-m, --monitor", "Start as monitor, do not auto cleanup network"))
.command("spawn")
.description("Spawn the network defined in the config")
.argument("<networkConfig>", "Network config file path")
.argument("[creds]", "kubeclt credentials file")
.argument(
"[monitor]",
"Monitor flag, don't teardown the network with the cronjob."
)
.action(spawn);

program
.addOption(
new Option("-p, --provider <provider>", "Override provider to use")
.choices(["podman", "kubernetes"])
.choices(["podman", "kubernetes", "native"])
.default("kubernetes", "kubernetes")
)
.command("test")
Expand Down
57 changes: 47 additions & 10 deletions src/cmdGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { Node } from "./types";
import { getRandomPort } from "./utils";

function parseCmdWithArguments(commandWithArgs: string): string[] {
function parseCmdWithArguments(commandWithArgs: string, useWrapper = true): string[] {
const parts = commandWithArgs.split(" ");
let finalCommand: string[] = [];
if (["bash", "ash"].includes(parts[0])) {
Expand All @@ -23,15 +23,18 @@ function parseCmdWithArguments(commandWithArgs: string): string[] {
}
finalCommand = [...finalCommand, ...[parts.slice(partIndex).join(" ")]];
} else {
finalCommand = ["/cfg/zombie-wrapper.sh", commandWithArgs];
finalCommand = [commandWithArgs];
if(useWrapper) finalCommand.unshift("/cfg/zombie-wrapper.sh");
}

return finalCommand;
}

export async function genCollatorCmd(
command: string,
nodeSetup: Node
nodeSetup: Node,
cfgPath: string = "/cfg",
useWrapper = true
): Promise<string[]> {
const { name, args, chain, bootnodes } = nodeSetup;
const parachainAddedArgs: any = {
Expand Down Expand Up @@ -71,7 +74,7 @@ export async function genCollatorCmd(
}

// Arguments for the relay chain node part of the collator binary.
fullCmd.push(...["--", "--chain", `/cfg/${chain}.json`]);
fullCmd.push(...["--", "--chain", `${cfgPath}/${chain}.json`]);

const collatorPorts: any = {
"--port": 0,
Expand Down Expand Up @@ -114,10 +117,11 @@ export async function genCollatorCmd(
}
}

return ["/cfg/zombie-wrapper.sh", ...fullCmd];
if(useWrapper) fullCmd.unshift("/cfg/zombie-wrapper.sh");
return fullCmd;
}

export async function genCmd(nodeSetup: Node): Promise<string[]> {
export async function genCmd(nodeSetup: Node, cfgPath: string = "/cfg", useWrapper = true, portFlags?: { [flag: string]: number } ): Promise<string[]> {
let {
name,
chain,
Expand All @@ -130,7 +134,7 @@ export async function genCmd(nodeSetup: Node): Promise<string[]> {
validator,
bootnodes,
args,
substrateRole,
zombieRole,
} = nodeSetup;

// fullCommand is NOT decorated by the `zombie` wrapper
Expand All @@ -145,7 +149,7 @@ export async function genCmd(nodeSetup: Node): Promise<string[]> {
if (!command) command = DEFAULT_COMMAND;

// IFF the node is a cumulus based collator
if (substrateRole === "collator" && !command.includes("adder")) {
if (zombieRole === "collator" && !command.includes("adder")) {
return await genCollatorCmd(command, nodeSetup);
}

Expand All @@ -161,10 +165,40 @@ export async function genCmd(nodeSetup: Node): Promise<string[]> {
if (bootnodes && bootnodes.length)
args.push("--bootnodes", bootnodes.join(","));


if(portFlags) {
// ensure port are set as desired
for(const flag of Object.keys(portFlags)) {
const index = args.findIndex( arg => arg === flag);
if(index < 0) args.push(...[flag, portFlags[flag].toString()]);
else {
args[index+1] = portFlags[flag].toString()
}
}

// special case for bootnode
// use `--listen-addr` to bind 0.0.0.0 and don't use `--port`.
// --listen-addr /ip4/0.0.0.0/tcp/30333
if(zombieRole === "bootnode") {
const port = portFlags["--port"];
const listenIndex = args.findIndex(arg => arg === "--listen-addr")
if(listenIndex >= 0) {
const parts = args[listenIndex+1].split("/");
parts[4] = port.toString();
args[listenIndex+1] = parts.join("/");
} else {
args.push(...["--listen-addr", `/ip4/0.0.0.0/tcp/${port}`])
}

const portFlagIndex = args.findIndex(arg => arg === "--port");
if(portFlagIndex >= 0) args.splice(portFlagIndex, 2);
}
}

const finalArgs: string[] = [
command,
"--chain",
`/cfg/${chain}.json`,
`${cfgPath}/${chain}.json`,
"--name",
name,
"--rpc-cors",
Expand All @@ -173,8 +207,11 @@ export async function genCmd(nodeSetup: Node): Promise<string[]> {
"--rpc-methods",
"unsafe",
"--unsafe-ws-external",
"--tmp",
...args,
];

return ["/cfg/zombie-wrapper.sh", finalArgs.join(" ")];
const resolvedCmd = [finalArgs.join(" ")];
if(useWrapper) resolvedCmd.unshift("/cfg/zombie-wrapper.sh");
return resolvedCmd;
}
31 changes: 16 additions & 15 deletions src/configManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ export const DEFAULT_BOOTNODE_PEER_ID =
"12D3KooWEyoppNCUx8Yx66oV9fJnriXwCcXwDDUA2kj6vnc6iDEp";
export const DEFAULT_BOOTNODE_DOMAIN = "bootnode";
export const DEFAULT_REMOTE_DIR = "/cfg";
export const DEFAULT_CHAIN_SPEC_PATH = "/cfg/{{chainName}}-plain.json";
export const DEFAULT_CHAIN_SPEC_RAW_PATH = "/cfg/{{chainName}}-raw.json";
export const DEFAULT_CHAIN_SPEC = "{{chainName}}-plain.json";
export const DEFAULT_CHAIN_SPEC_RAW = "{{chainName}}-raw.json";
export const DEFAULT_CHAIN_SPEC_COMMAND =
"polkadot build-spec --chain {{chainName}} --disable-default-bootnode";
"{{DEFAULT_COMMAND}} build-spec --chain {{chainName}} --disable-default-bootnode";
export const DEFAULT_GENESIS_GENERATE_SUBCOMMAND ="export-genesis-state";
export const DEFAULT_WASM_GENERATE_SUBCOMMAND = "export-genesis-wasm";
export const DEFAULT_ADDER_COLLATOR_BIN = "/usr/local/bin/adder-collator";
export const DEFAULT_CUMULUS_COLLATOR_BIN = "/usr/local/bin/polkadot-collator";
export const DEFAULT_ADDER_COLLATOR_BIN = "adder-collator";
export const DEFAULT_CUMULUS_COLLATOR_BIN = "polkadot-collator";
export const DEFAULT_COLLATOR_IMAGE = "paritypr/colander:4131-e5c7e975";
export const FINISH_MAGIC_FILE = "/tmp/finished.txt";
export const GENESIS_STATE_FILENAME = "genesis-state";
Expand All @@ -63,7 +63,7 @@ export const zombieWrapperPath = resolve(
export const LOKI_URL_FOR_NODE =
"https://grafana.parity-mgmt.parity.io/explore?orgId=1&left=%5B%22now-3h%22,%22now%22,%22loki.parity-zombienet%22,%7B%22expr%22:%22%7Bpod%3D~%5C%22{{namespace}}%2F{{podName}}%5C%22%7D%22,%22refId%22:%22A%22,%22range%22:true%7D%5D";

export const AVAILABLE_PROVIDERS = ["podman", "kubernetes"];
export const AVAILABLE_PROVIDERS = ["podman", "kubernetes", "native"];

export async function generateNetworkSpec(
config: LaunchConfig
Expand All @@ -87,6 +87,7 @@ export async function generateNetworkSpec(
let networkSpec: any = {
relaychain: {
defaultImage: config.relaychain.default_image || DEFAULT_IMAGE,
defaultCommand: config.relaychain.default_command || DEFAULT_COMMAND,
nodes: [],
chain: config.relaychain.chain,
overrides: Promise.all(globalOverrides),
Expand Down Expand Up @@ -124,15 +125,15 @@ export async function generateNetworkSpec(
.chain_spec_command
? config.relaychain.chain_spec_command
: DEFAULT_CHAIN_SPEC_COMMAND.replace(
new RegExp("{{chainName}}", "g"),
"{{chainName}}",
chainName
);
).replace("{{DEFAULT_COMMAND}}", networkSpec.relaychain.defaultCommand);
}

for (const node of config.relaychain.nodes) {
const command = node.command
? node.command
: config.relaychain.default_command;
: networkSpec.relaychain.defaultCommand;
const image = node.image ? node.image : config.relaychain.default_image;
let args: string[] = [];
if (node.args) args = args.concat(node.args);
Expand Down Expand Up @@ -245,7 +246,7 @@ export async function generateNetworkSpec(
computedStateCommand += ` --parachain-id ${parachain.id}`;
}

computedStateCommand += ` > ${DEFAULT_REMOTE_DIR}/${GENESIS_STATE_FILENAME}`;
computedStateCommand += ` > {{CLIENT_REMOTE_DIR}}/${GENESIS_STATE_FILENAME}`;
}

if (parachain.genesis_wasm_path) {
Expand All @@ -265,7 +266,7 @@ export async function generateNetworkSpec(
} else {
computedWasmCommand = parachain.genesis_wasm_generator
? parachain.genesis_wasm_generator
: `${collatorBinary} ${DEFAULT_WASM_GENERATE_SUBCOMMAND} > ${DEFAULT_REMOTE_DIR}/${GENESIS_WASM_FILENAME}`;
: `${collatorBinary} ${DEFAULT_WASM_GENERATE_SUBCOMMAND} > {{CLIENT_REMOTE_DIR}}/${GENESIS_WASM_FILENAME}`;
}

let args: string[] = [];
Expand All @@ -289,8 +290,7 @@ export async function generateNetworkSpec(
chain: chainName,
args: [],
env: env,
bootnodes,
substrateRole: "collator",
bootnodes
},
};

Expand All @@ -314,13 +314,13 @@ export async function generateNetworkSpec(
networkSpec.types = config.types ? config.types : {};
networkSpec.configBasePath = config.configBasePath;

return networkSpec;
return networkSpec as ComputedNetwork;
}

export function generateBootnodeSpec(config: ComputedNetwork): Node {
const nodeSetup: Node = {
name: "bootnode",
command: DEFAULT_COMMAND,
command: config.relaychain.defaultCommand || DEFAULT_COMMAND,
image: config.relaychain.defaultImage || DEFAULT_IMAGE,
chain: config.relaychain.chain,
port: P2P_PORT,
Expand All @@ -338,6 +338,7 @@ export function generateBootnodeSpec(config: ComputedNetwork): Node {
bootnodes: [],
telemetryUrl: "",
overrides: [],
zombieRole: "bootnode"
};

return nodeSetup;
Expand Down
17 changes: 11 additions & 6 deletions src/networkNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export class NetworkNode implements NetworkNodeInterface {
userDefinedTypes: any;
parachainId?: number;
lastLogLineCheckedTimestamp?: string;
lastLogLineCheckedIndex?: number;

constructor(
name: string,
Expand Down Expand Up @@ -272,16 +273,19 @@ export class NetworkNode implements NetworkNodeInterface {

// By default use 2s since we sleep 1s.
const logs = await client.getNodeLogs(this.name, 2, true);
const dedupedLogs = this._dedupLogs(logs.split("\n"));
const dedupedLogs = this._dedupLogs(logs.split("\n"), client.providerName === "native");
const index = dedupedLogs.findIndex(line => {
// remove the extra timestamp
return re.test(line.split(" ").slice(1).join(" "));

if(client.providerName !== "native") {
// remove the extra timestamp
line = line.split(" ").slice(1).join(" ")
}
return re.test(line);
});

if(index >= 0) {
done = true;
this.lastLogLineCheckedTimestamp = dedupedLogs[index];
this.lastLogLineCheckedIndex = index;
debug(this.lastLogLineCheckedTimestamp.split(" ").slice(1).join(" "));
clearTimeout(limitTimeout);
} else {
Expand All @@ -298,14 +302,15 @@ export class NetworkNode implements NetworkNodeInterface {
}

// prevent to seach in the same log line twice.
_dedupLogs(logs: string[]): string[] {
_dedupLogs(logs: string[], useIndex = false): string[] {
if( ! this.lastLogLineCheckedTimestamp) return logs;
if(useIndex) return logs.slice(this.lastLogLineCheckedIndex);

const lastLineTs = this.lastLogLineCheckedTimestamp.split(" ")[0];
const index = logs.findIndex(logLine => {
const thisLineTs = logLine.split(" ")[0];
return ( thisLineTs > lastLineTs );
});

return logs.slice(index);
}

Expand Down
Loading

0 comments on commit 92f2a68

Please sign in to comment.