mirror of
https://github.com/EvernodeXRPL/hp-devkit.git
synced 2026-04-29 15:37:58 +00:00
Spawn and Status commands with refactoring. (#21)
This commit is contained in:
@@ -14,12 +14,12 @@ user_port_begin=$HP_USER_PORT_BEGIN
|
||||
peer_port_begin=$HP_PEER_PORT_BEGIN
|
||||
|
||||
if [ "$command" = "create" ] || [ "$command" = "bindmesh" ] || [ "$command" = "destroy" ] || \
|
||||
[ "$command" = "start" ] || [ "$command" = "stop" ] || \
|
||||
[ "$command" = "logs" ] || [ "$command" = "sync" ] ; then
|
||||
[ "$command" = "start" ] || [ "$command" = "stop" ] || [ "$command" = "spawn" ] || \
|
||||
[ "$command" = "logs" ] || [ "$command" = "sync" ] || [ "$command" = "status" ] ; then
|
||||
echo "sub-command: $command"
|
||||
else
|
||||
echo "Invalid sub-command."
|
||||
echo "Expected: create | destroy | start | stop | logs | sync"
|
||||
echo "Expected: create | destroy | start | stop | spawn | logs | sync | status"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -159,7 +159,7 @@ function bind_mesh {
|
||||
local contract_dir=$(contract_dir_mount_path $node)
|
||||
local cfg_file=$contract_dir/cfg/hp.cfg
|
||||
local peers=$(joinarr all_peers $instance_count $i)
|
||||
jq ".contract.unl=$unl | .mesh.known_peers=$peers" $cfg_file > $cfg_file.tmp && mv $cfg_file.tmp $cfg_file
|
||||
jq ".contract.unl=$unl | .mesh.known_peers=$peers | .contract.consensus.mode=\"public\"" $cfg_file > $cfg_file.tmp && mv $cfg_file.tmp $cfg_file
|
||||
done
|
||||
}
|
||||
|
||||
@@ -202,6 +202,47 @@ function destroy_cluster {
|
||||
exists "network" $network && docker network rm $network
|
||||
}
|
||||
|
||||
function spawn_node {
|
||||
ensure_cluser_exists
|
||||
|
||||
local old_count=$(get_container_count)
|
||||
local new_id=$((old_count+1))
|
||||
create_instance $new_id
|
||||
|
||||
local tmp_dir=$(mktemp -d /tmp/hpdevkit.spawn.XXXXXX)
|
||||
local node1_cfg=$(contract_dir_mount_path 1)/cfg/hp.cfg
|
||||
local new_cfg=$(contract_dir_mount_path $new_id)/cfg/hp.cfg
|
||||
|
||||
# Override new node's contract id and unl from the information from node1.
|
||||
|
||||
# Copy node1 cfg to temp file and remove the information we don't need.
|
||||
jq 'del(.contract,.node.public_key,.node.private_key)' $node1_cfg > $tmp_dir/a.json
|
||||
jq '{contract:{id:.contract.id,execute:.contract.execute,unl:.contract.unl,log}}' $node1_cfg > $tmp_dir/b.json
|
||||
jq -s '.[0] * .[1]' $tmp_dir/a.json $tmp_dir/b.json > $tmp_dir/from-node1.json
|
||||
|
||||
# Copy new cfg to temp file and remove the information we don't need.
|
||||
jq 'del(.contract.unl,.contract.id)' $new_cfg > $tmp_dir/from-newnode.json
|
||||
|
||||
jq -s '.[0] * .[1]' $tmp_dir/from-node1.json $tmp_dir/from-newnode.json > $tmp_dir/merged.json
|
||||
|
||||
# Inject the list of all known peers.
|
||||
local all_peers
|
||||
for ((i=1; i<=$old_count; i++));
|
||||
do
|
||||
# Assign peer ports in incrementing order.
|
||||
let peer_port=$(($peer_port_begin + $i - 1))
|
||||
all_peers[i]="node$i:${peer_port}"
|
||||
done
|
||||
local peers_json=$(joinarr all_peers $old_count -1)
|
||||
jq ".mesh.known_peers=$peers_json" $tmp_dir/merged.json > $new_cfg
|
||||
|
||||
# Cleanup temp dir.
|
||||
rm -r $tmp_dir
|
||||
|
||||
# Start the new node.
|
||||
change_cluster_status start $new_id
|
||||
}
|
||||
|
||||
function change_cluster_status {
|
||||
ensure_cluser_exists
|
||||
|
||||
@@ -220,7 +261,9 @@ function change_cluster_status {
|
||||
|
||||
function attach_logs {
|
||||
! cluster_exists && echo "Cluster '$cluster' does not exist." && exit 1
|
||||
local container_name="${container_prefix}_$1"
|
||||
local node=$1
|
||||
[ "$1" -eq "999999" ] && node=$(get_container_count)
|
||||
local container_name="${container_prefix}_$node"
|
||||
docker logs -f --tail=5 $container_name
|
||||
}
|
||||
|
||||
@@ -250,6 +293,9 @@ function sync_contract_bundle {
|
||||
sync_instance $i &
|
||||
done
|
||||
wait
|
||||
|
||||
# Cleanup the original contract bundle dir which is used to sync from.
|
||||
rm -r $bundle_mount/*
|
||||
}
|
||||
|
||||
function validate_port_begin {
|
||||
@@ -257,6 +303,10 @@ function validate_port_begin {
|
||||
! validate_port $peer_port_begin && echo "Invalid peer port begin." && exit 1
|
||||
}
|
||||
|
||||
function show_status {
|
||||
docker ps -a --format "table {{.Names}}\\t{{.State}}" | grep $container_prefix | sort
|
||||
}
|
||||
|
||||
if [ $command = "create" ]; then
|
||||
! validate_node_num_arg $cluster_size && echo "Invalid cluster size." && exit 1
|
||||
validate_port_begin
|
||||
@@ -270,9 +320,13 @@ elif [ $command = "start" ]; then
|
||||
change_cluster_status start $2
|
||||
elif [ $command = "stop" ]; then
|
||||
change_cluster_status stop $2
|
||||
elif [ $command = "spawn" ]; then
|
||||
spawn_node
|
||||
elif [ $command = "logs" ]; then
|
||||
! validate_node_num_arg $2 && echo "Usage: logs <node id>" && exit 1
|
||||
attach_logs $2
|
||||
elif [ $command = "sync" ]; then
|
||||
sync_contract_bundle
|
||||
elif [ $command = "status" ]; then
|
||||
show_status
|
||||
fi
|
||||
52
npm/index.js
52
npm/index.js
@@ -1,52 +1,62 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
const { program } = require('commander');
|
||||
const { version, codeGen, deploy, clean, logs, start, stop, update, uninstall } = require('./lib/command-handler');
|
||||
const commands = require('./lib/commands');
|
||||
|
||||
program
|
||||
.command('version')
|
||||
.description('hpdevkit version')
|
||||
.action(version);
|
||||
.description('Display the hpdevkit version.')
|
||||
.action(commands.version);
|
||||
|
||||
program
|
||||
.command('gen <platform> <app-type> <project-name>')
|
||||
.description('hpdevkit gen <platform> <app-type> <project-name>')
|
||||
.action(codeGen);
|
||||
.description('Generate HotPocket application development projects.')
|
||||
.action(commands.codeGen);
|
||||
|
||||
program
|
||||
.command('deploy <contract-path>')
|
||||
.description('hpdevkit deploy <contract-path>')
|
||||
.action(deploy);
|
||||
.description('Deploy the specified directory to a HotPocket cluster.')
|
||||
.action(commands.deploy);
|
||||
|
||||
program
|
||||
.command('clean')
|
||||
.description('hpdevkit clean')
|
||||
.action(clean);
|
||||
.description('Destroy the HotPocket cluster.')
|
||||
.action(commands.clean);
|
||||
|
||||
program
|
||||
.command('logs <node-number>')
|
||||
.description('hpdevkit logs <node-number>')
|
||||
.action(logs);
|
||||
.description('Display logs of the specified node.')
|
||||
.action(commands.logs);
|
||||
|
||||
program
|
||||
.command('start <node-number>')
|
||||
.description('hpdevkit start <node-number>')
|
||||
.action(start);
|
||||
.command('start [node-number]')
|
||||
.description('Start the specified node. Starts all nodes if unspecified.')
|
||||
.action(commands.start);
|
||||
|
||||
program
|
||||
.command('stop <node-number>')
|
||||
.description('hpdevkit stop <node-number>')
|
||||
.action(stop);
|
||||
.command('stop [node-number]')
|
||||
.description('Stop the specified node. Stops all nodes if unspecified.')
|
||||
.action(commands.stop);
|
||||
|
||||
program
|
||||
.command('spawn')
|
||||
.description('Create a fresh node which connects to the existing cluster.')
|
||||
.action(commands.spawn);
|
||||
|
||||
program
|
||||
.command('status')
|
||||
.description('Display status of running nodes.')
|
||||
.action(commands.status);
|
||||
|
||||
program
|
||||
.command('update')
|
||||
.description('hpdevkit update')
|
||||
.action(update);
|
||||
.description('Update hpdevkit.')
|
||||
.action(commands.update);
|
||||
|
||||
program
|
||||
.command('uninstall')
|
||||
.description('uninstall')
|
||||
.action(uninstall);
|
||||
.description('Uninstall hpdevkit.')
|
||||
.action(commands.uninstall);
|
||||
|
||||
try {
|
||||
program.parse();
|
||||
|
||||
@@ -4,12 +4,12 @@ const { exec } = require('./child-proc');
|
||||
const {
|
||||
CONSTANTS,
|
||||
initializeDeploymentCluster,
|
||||
runOnContainer,
|
||||
executeOnContainer,
|
||||
runOnNewContainer,
|
||||
executeOnManagementContainer,
|
||||
teardownDeploymentCluster,
|
||||
isExists,
|
||||
updateDockerImages
|
||||
} = require('./common');
|
||||
} = require('./docker-helpers');
|
||||
const { success, error, info, warn } = require('./logger');
|
||||
|
||||
function version() {
|
||||
@@ -37,7 +37,7 @@ function codeGen(platform, apptype, projName) {
|
||||
}
|
||||
|
||||
try {
|
||||
runOnContainer(CONSTANTS.codegenContainerName, null, null, null, null, `${platform} ${apptype} ${projName}`, 'codegen');
|
||||
runOnNewContainer(CONSTANTS.codegenContainerName, null, null, null, null, `${platform} ${apptype} ${projName}`, 'codegen');
|
||||
exec(`docker cp ${CONSTANTS.codegenContainerName}:${CONSTANTS.codegenOutputDir} ./${projName}`);
|
||||
success(`Project '${projName}' created.`);
|
||||
}
|
||||
@@ -60,18 +60,24 @@ function deploy(contractPath) {
|
||||
`rm -rf ${CONSTANTS.bundleMount}` :
|
||||
`mkdir -p ${CONSTANTS.bundleMount} && rm -rf ${CONSTANTS.bundleMount}/* ${CONSTANTS.bundleMount}/.??*`;
|
||||
|
||||
executeOnContainer(CONSTANTS.deploymentContainerName, prepareBundleDir);
|
||||
exec(`docker cp ${contractPath} "${CONSTANTS.deploymentContainerName}:${CONSTANTS.bundleMount}"`);
|
||||
executeOnManagementContainer(prepareBundleDir);
|
||||
exec(`docker cp ${contractPath} "${CONSTANTS.managementContainerName}:${CONSTANTS.bundleMount}"`);
|
||||
|
||||
// Sync contract bundle to all instance directories in the cluster.
|
||||
executeOnContainer(CONSTANTS.deploymentContainerName, 'cluster stop ; cluster sync ; cluster start');
|
||||
executeOnManagementContainer('cluster stop ; cluster sync ; cluster start');
|
||||
|
||||
if (appenv.defaultNode > 0) {
|
||||
info(`Streaming logs of node ${appenv.defaultNode}:`);
|
||||
executeOnContainer(CONSTANTS.deploymentContainerName, `cluster logs ${appenv.defaultNode}`);
|
||||
executeOnManagementContainer(`cluster logs ${appenv.defaultNode}`);
|
||||
}
|
||||
}
|
||||
|
||||
function spawn() {
|
||||
info(`command: spawn (cluster: ${appenv.cluster})`);
|
||||
|
||||
executeOnManagementContainer('cluster spawn && cluster logs 999999');
|
||||
}
|
||||
|
||||
function clean() {
|
||||
info(`command: clean (cluster: ${appenv.cluster})`);
|
||||
|
||||
@@ -81,19 +87,25 @@ function clean() {
|
||||
function logs(nodeNumber) {
|
||||
info(`command: logs (cluster: ${appenv.cluster})`);
|
||||
|
||||
runOnContainer(null, null, true, true, null, `logs ${nodeNumber}`, 'cluster');
|
||||
executeOnManagementContainer(`cluster logs ${nodeNumber}`);
|
||||
}
|
||||
|
||||
function start(nodeNumber) {
|
||||
info(`command: start (cluster: ${appenv.cluster})`);
|
||||
|
||||
runOnContainer(null, null, true, true, null, `start ${nodeNumber}`, 'cluster');
|
||||
executeOnManagementContainer(`cluster start ${nodeNumber}`);
|
||||
}
|
||||
|
||||
function stop(nodeNumber) {
|
||||
info(`command: stop (cluster: ${appenv.cluster})`);
|
||||
|
||||
runOnContainer(null, null, true, true, null, `stop ${nodeNumber}`, 'cluster');
|
||||
executeOnManagementContainer(`cluster stop ${nodeNumber}`);
|
||||
}
|
||||
|
||||
function status() {
|
||||
info(`command: status (cluster: ${appenv.cluster})`);
|
||||
|
||||
executeOnManagementContainer(`cluster status`);
|
||||
}
|
||||
|
||||
function update() {
|
||||
@@ -124,7 +136,7 @@ function uninstall() {
|
||||
exec(`npm -g uninstall ${CONSTANTS.npmPackageName}`, true);
|
||||
|
||||
// Remove deployment cluster if exist.
|
||||
if (isExists(CONSTANTS.deploymentContainerName)) {
|
||||
if (isExists(CONSTANTS.managementContainerName)) {
|
||||
info('\nCleaning the deployed contracts...');
|
||||
teardownDeploymentCluster();
|
||||
}
|
||||
@@ -151,6 +163,8 @@ module.exports = {
|
||||
logs,
|
||||
start,
|
||||
stop,
|
||||
spawn,
|
||||
status,
|
||||
update,
|
||||
uninstall
|
||||
};
|
||||
@@ -3,7 +3,6 @@ const { exec } = require("./child-proc");
|
||||
const { log, info } = require("./logger");
|
||||
|
||||
const GLOBAL_PREFIX = "hpdevkit";
|
||||
const VERSION = "0.1.0";
|
||||
|
||||
const CONSTANTS = {
|
||||
npmPackageName: `hpdevkit`,
|
||||
@@ -12,7 +11,7 @@ const CONSTANTS = {
|
||||
network: `${GLOBAL_PREFIX}_${appenv.cluster}_net`,
|
||||
containerPrefix: `${GLOBAL_PREFIX}_${appenv.cluster}_node`,
|
||||
bundleMount: `${GLOBAL_PREFIX}_vol/contract_bundle`,
|
||||
deploymentContainerName: `${GLOBAL_PREFIX}_${appenv.cluster}_deploymgr`,
|
||||
managementContainerName: `${GLOBAL_PREFIX}_${appenv.cluster}_deploymgr`,
|
||||
confOverrideFile: "hp.cfg.override",
|
||||
codegenOutputDir: "/codegen-output",
|
||||
codegenContainerName: `${GLOBAL_PREFIX}_codegen`,
|
||||
@@ -20,7 +19,7 @@ const CONSTANTS = {
|
||||
prerequisiteInstaller: "install.sh"
|
||||
};
|
||||
|
||||
function runOnContainer(name, detached, autoRemove, mountStock, mountVolume, entryCmd, entryPoint, interactive = true, restart = null) {
|
||||
function runOnNewContainer(name, detached, autoRemove, mountSock, mountVolume, entryCmd, entryPoint, interactive = true, restart = null) {
|
||||
command = `docker run`;
|
||||
|
||||
if (interactive)
|
||||
@@ -35,7 +34,7 @@ function runOnContainer(name, detached, autoRemove, mountStock, mountVolume, ent
|
||||
if (autoRemove)
|
||||
command += " --rm";
|
||||
|
||||
if (mountStock)
|
||||
if (mountSock)
|
||||
command += " --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock";
|
||||
|
||||
if (mountVolume)
|
||||
@@ -71,6 +70,15 @@ function executeOnContainer(name, cmd) {
|
||||
exec(`docker exec ${name} /bin/bash -c "${cmd}"`, true);
|
||||
}
|
||||
|
||||
function executeOnManagementContainer(cmd) {
|
||||
if (!isExists(CONSTANTS.managementContainerName)) {
|
||||
info(`cluster '${appenv.cluster}' not found.`)
|
||||
return;
|
||||
}
|
||||
|
||||
executeOnContainer(CONSTANTS.managementContainerName, cmd)
|
||||
}
|
||||
|
||||
function isExists(name, type = null) {
|
||||
try {
|
||||
const res = exec(`docker ${type === 'image' ? 'image ' : ''}inspect ${name}`);
|
||||
@@ -85,26 +93,26 @@ function isExists(name, type = null) {
|
||||
}
|
||||
|
||||
function initializeDeploymentCluster() {
|
||||
if (!isExists(CONSTANTS.deploymentContainerName)) {
|
||||
if (!isExists(CONSTANTS.managementContainerName)) {
|
||||
log("\nInitializing deployment cluster");
|
||||
|
||||
// Stop cluster if running. Create cluster if not exists.
|
||||
runOnContainer(CONSTANTS.deploymentContainerName, null, true, true, null, 'cluster stop ; cluster create', null);
|
||||
runOnNewContainer(CONSTANTS.managementContainerName, null, true, true, null, 'cluster stop ; cluster create', null);
|
||||
|
||||
// Spin up management container.
|
||||
runOnContainer(CONSTANTS.deploymentContainerName, true, false, true, true, null, null, true, 'unless-stopped');
|
||||
runOnNewContainer(CONSTANTS.managementContainerName, true, false, true, true, null, null, true, 'unless-stopped');
|
||||
|
||||
// Bind the instance mesh network config together.
|
||||
executeOnContainer(CONSTANTS.deploymentContainerName, 'cluster bindmesh');
|
||||
executeOnContainer(CONSTANTS.managementContainerName, 'cluster bindmesh');
|
||||
}
|
||||
}
|
||||
|
||||
function teardownDeploymentCluster() {
|
||||
if (isExists(CONSTANTS.deploymentContainerName)) {
|
||||
exec(`docker stop ${CONSTANTS.deploymentContainerName}`);
|
||||
exec(`docker rm ${CONSTANTS.deploymentContainerName}`);
|
||||
if (isExists(CONSTANTS.managementContainerName)) {
|
||||
exec(`docker stop ${CONSTANTS.managementContainerName}`);
|
||||
exec(`docker rm ${CONSTANTS.managementContainerName}`);
|
||||
}
|
||||
runOnContainer(null, null, true, true, null, "cluster stop ; cluster destroy", null, false);
|
||||
runOnNewContainer(null, null, true, true, null, "cluster stop ; cluster destroy", null, false);
|
||||
}
|
||||
|
||||
function updateDockerImages() {
|
||||
@@ -112,15 +120,16 @@ function updateDockerImages() {
|
||||
exec(`docker pull ${appenv.instanceImage}`, true);
|
||||
|
||||
// Clear if there's already deployed cluster since they are outdated now.
|
||||
if (isExists(CONSTANTS.deploymentContainerName)) {
|
||||
if (isExists(CONSTANTS.managementContainerName)) {
|
||||
info('\nCleaning the deployed contracts...');
|
||||
teardownDeploymentCluster();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
runOnContainer,
|
||||
runOnNewContainer,
|
||||
executeOnContainer,
|
||||
executeOnManagementContainer,
|
||||
isExists,
|
||||
initializeDeploymentCluster,
|
||||
teardownDeploymentCluster,
|
||||
4
npm/package-lock.json
generated
4
npm/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "hpdevkit",
|
||||
"version": "0.5.6",
|
||||
"version": "0.5.7",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "hpdevkit",
|
||||
"version": "0.5.6",
|
||||
"version": "0.5.7",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hpdevkit",
|
||||
"version": "0.5.6",
|
||||
"version": "0.5.7",
|
||||
"description": "Developer toolkit for HotPocket smart contract development",
|
||||
"scripts": {
|
||||
"install": "node scripts/install.js"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
const { updateDockerImages } = require("../lib/common");
|
||||
const { updateDockerImages } = require("../lib/docker-helpers");
|
||||
|
||||
updateDockerImages();
|
||||
Reference in New Issue
Block a user