UNPKG

@zombienet/orchestrator

Version:

ZombieNet aim to be a testing framework for substrate based blockchains, providing a simple cli tool that allow users to spawn and test ephemeral Substrate based networks

158 lines (157 loc) 8.38 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.spawnNode = void 0; const utils_1 = require("@zombienet/utils"); const path_1 = __importDefault(require("path")); const bootnode_1 = require("./bootnode"); const chainSpec_1 = require("./chainSpec"); const constants_1 = require("./constants"); const keys_1 = require("./keys"); const network_1 = require("./network"); const networkNode_1 = require("./networkNode"); const providers_1 = require("./providers"); const sharedTypes_1 = require("./sharedTypes"); const debug = require("debug")("zombie::spawner"); const spawnNode = (client, node, network, bootnodes, filesToCopy, opts, parachain) => __awaiter(void 0, void 0, void 0, function* () { var _a, _b, _c, _d; const namespace = client.namespace; const { genBootnodeDef, genNodeDef, replaceNetworkRef } = (0, providers_1.getProvider)(client.providerName); let parachainSpecId; // for relay chain we can have more than one bootnode. if ([sharedTypes_1.ZombieRole.Node, sharedTypes_1.ZombieRole.Collator].includes(node.zombieRole)) node.bootnodes = node.bootnodes.concat(bootnodes); if (opts.jaegerUrl) node.jaegerUrl = opts.jaegerUrl; debug(`creating node: ${node.name}`); const podDef = yield (node.name === "bootnode" ? genBootnodeDef(namespace, node) : genNodeDef(namespace, node, opts.inCI)); const finalFilesToCopyToNode = [...filesToCopy]; // add spec file if is provided if (parachain === null || parachain === void 0 ? void 0 : parachain.specPath) { finalFilesToCopyToNode.push({ localFilePath: parachain.specPath, remoteFilePath: `${client.remoteDir}/${node.chain}-${parachain.id}.json`, }); parachainSpecId = yield (0, chainSpec_1.getChainIdFromSpec)(parachain.specPath); } for (const override of node.overrides) { finalFilesToCopyToNode.push({ localFilePath: override.local_path, remoteFilePath: `${client.remoteDir}/${override.remote_name}`, }); } let keystoreLocalDir; if (node.accounts) { // check if the node directory exists if not create (e.g for k8s provider) let nodeFilesPath = client.tmpDir; if (parachain && parachain.name) nodeFilesPath += `/${parachain.name}`; nodeFilesPath += `/${node.name}`; yield (0, utils_1.makeDir)(nodeFilesPath, true); const isAssetHubPolkadot = parachain && (((_a = parachain.chain) === null || _a === void 0 ? void 0 : _a.includes("statemint")) || ((_b = parachain.chain) === null || _b === void 0 ? void 0 : _b.includes("asset-hub-polkadot")) || ((_c = parachain.chainSpecPath) === null || _c === void 0 ? void 0 : _c.includes("statemint")) || ((_d = parachain.chainSpecPath) === null || _d === void 0 ? void 0 : _d.includes("asset-hub-polkadot"))); const keystoreFiles = yield (0, keys_1.generateKeystoreFiles)(node, nodeFilesPath, isAssetHubPolkadot); keystoreLocalDir = path_1.default.dirname(keystoreFiles[0]); } // replace all network references in command replaceNetworkRef(podDef, network); yield client.spawnFromDef(podDef, finalFilesToCopyToNode, keystoreLocalDir, parachainSpecId || network.chainId, node.dbSnapshot, true); const [nodeIp, nodePort] = yield client.getNodeInfo(podDef.metadata.name); const nodeMultiAddress = yield (0, bootnode_1.generateNodeMultiAddress)(node.key, node.args, nodeIp, nodePort, true, node.p2pCertHash); let networkNode; const endpointPort = node.substrateCliArgsVersion == 0 ? constants_1.RPC_WS_PORT : constants_1.RPC_HTTP_PORT; if (opts.inCI) { // UPDATE: 04-10-2024 Since we have several reports of failures related to // can't access metrics by dns, we switch back to use the pod ip. // in CI we deploy a service (with the pod name) in front of each pod // so here we can use the name (as short dns in the ns) to connect to pod. // const nodeDns = `${podDef.metadata.name}.${namespace}.svc.cluster.local`; const pod_ip = yield client.getNodeIP(node.name); networkNode = new networkNode_1.NetworkNode(node.name, constants_1.WS_URI_PATTERN.replace("{{IP}}", pod_ip).replace("{{PORT}}", endpointPort.toString()), constants_1.METRICS_URI_PATTERN.replace("{{IP}}", pod_ip).replace("{{PORT}}", constants_1.PROMETHEUS_PORT.toString()), nodeMultiAddress, opts.userDefinedTypes, node.prometheusPrefix); } else { const external_port = node.externalPorts[node.substrateCliArgsVersion == 0 ? "wsPort" : "rpcPort"]; const nodeIdentifier = `service/${podDef.metadata.name}`; const fwdPort = yield client.startPortForwarding(endpointPort, nodeIdentifier, namespace, external_port); const external_port_prom = node.externalPorts["prometheusPort"]; const nodePrometheusPort = yield client.startPortForwarding(constants_1.PROMETHEUS_PORT, nodeIdentifier, namespace, external_port_prom); const listeningIp = opts.local_ip || constants_1.LOCALHOST; networkNode = new networkNode_1.NetworkNode(node.name, constants_1.WS_URI_PATTERN.replace("{{IP}}", listeningIp).replace("{{PORT}}", fwdPort.toString()), constants_1.METRICS_URI_PATTERN.replace("{{IP}}", listeningIp).replace("{{PORT}}", nodePrometheusPort.toString()), nodeMultiAddress, opts.userDefinedTypes, node.prometheusPrefix); } networkNode.group = node.group; // add the full spec networkNode.spec = node; if (parachain) { const paraId = parachain.id; if (!network.paras[paraId]) network.addPara(paraId, parachain.specPath, parachain.wasmPath, parachain.statePath); networkNode.parachainId = paraId; networkNode.para = parachain.para; network.addNode(networkNode, network_1.Scope.PARA); } else { network.addNode(networkNode, network_1.Scope.RELAY); } // Display info about the current node const logTable = new utils_1.CreateLogTable({ colWidths: [20, 100], doubleBorder: true, }); logTable.pushTo([ ["Pod", utils_1.decorators.green(node.name)], ["Status", utils_1.decorators.green("Running")], ]); if (node.overrides && node.overrides.length > 0) { logTable.pushTo([ [ { colSpan: 2, content: `with ${utils_1.decorators.yellow("Overrides")}...`, }, ], ]); for (const override of node.overrides) { logTable.pushTo([ ["local_path", override.local_path], ["remote name", override.remote_name], ]); } } if (opts.monitorIsAvailable) { const loki_url = (0, utils_1.getLokiUrl)(namespace, podDef.metadata.name, network.networkStartTime); logTable.pushTo([ [utils_1.decorators.green("Grafana logs url"), utils_1.decorators.magenta(loki_url)], ]); } else { logTable.pushTo([ [ { colSpan: 2, content: utils_1.decorators.magenta("You can follow the logs of the node by running this command: "), }, ], ]); logTable.print(); if (opts.logType !== "silent") console.log(client.getLogsCommand(podDef.metadata.name) + "\n\n"); } return nodeMultiAddress; }); exports.spawnNode = spawnNode;