Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inital implementation of native provider #66

Merged
merged 4 commits into from
Jan 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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