Compare commits

...
Author SHA1 Message Date
telackey 1def279d26 Support multiple NodePorts, static NodePort mapping, and add 'replicas' spec option (#913)
NodePort example:

```
network:
  ports:
    caddy:
     - 1234
     - 32020:2020
```

Replicas example:

```
replicas: 2
```

This also adds an optimization for k8s where if a directory matching the name of a configmap exists in beneath config/ in the stack, its contents will be copied into the corresponding configmap.

For example:

```
# Config files in the stack
❯ ls stack-orchestrator/config/caddyconfig
Caddyfile  Caddyfile.one-req-per-upstream-example

# ConfigMap in the spec
❯ cat foo.yml | grep config
...
configmaps:
  caddyconfig: ./configmaps/caddyconfig

# Create the deployment
❯ laconic-so --stack ~/cerc/caddy-ethcache/stack-orchestrator/stacks/caddy-ethcache deploy create --spec-file foo.yml

# The files from beneath config/<config_map_name> have been copied to the ConfigMap directory from the spec.
❯ ls deployment-001/configmaps/caddyconfig
Caddyfile  Caddyfile.one-req-per-upstream-example
```

Reviewed-on: cerc-io/stack-orchestrator#913
Reviewed-by: David Boreham <dboreham@noreply.git.vdb.to>
Co-authored-by: Thomas E Lackey <telackey@bozemanpass.com>
Co-committed-by: Thomas E Lackey <telackey@bozemanpass.com>
2024-08-09 02:32:06 +00:00
dboreham 64691bd206 Merge pull request 'Allow gentx-files to be omitted' (#911) from dboreham/allow-zero-gentx into main
Reviewed-on: cerc-io/stack-orchestrator#911
2024-08-07 20:13:40 +00:00
dboreham aef5986135 Allow gentx-files to be omitted 2024-08-07 14:11:06 -06:00
dboreham 6f8f0340d3 Merge pull request 'Add stage 1 support' (#910) from dboreham/stage1-support into main
Reviewed-on: cerc-io/stack-orchestrator#910
2024-08-07 17:44:28 +00:00
dboreham 7590d6e237 Add stage 1 support 2024-08-07 11:28:10 -06:00
dboreham 573f99dbbe Listen on 0.0.0.0 (#909)
Reviewed-on: cerc-io/stack-orchestrator#909
Co-authored-by: David Boreham <david@bozemanpass.com>
Co-committed-by: David Boreham <david@bozemanpass.com>
2024-08-02 14:06:06 +00:00
dboreham 8052c1c25e Merge pull request 'Laconicd needs to be told its currency' (#908) from dboreham/mainnet-laconic-specify-currency into main
Reviewed-on: cerc-io/stack-orchestrator#908
2024-08-02 03:10:34 +00:00
dboreham a674d13493 Laconicd needs to be told its currency 2024-08-01 21:09:30 -06:00
roysc 0d4f4509c8 Remove Eth fixturenet workflows (#906)
Deletes the now-failing CI workflows for the old `fixturenet-eth` and `fixturenet-plugeth` stacks.

Part of cerc-io/stack-orchestrator#905.

Reviewed-on: cerc-io/stack-orchestrator#906
Reviewed-by: David Boreham <dboreham@noreply.git.vdb.to>
2024-08-01 02:28:05 +00:00
dboreham 5af27b1b3a Merge pull request 'Fix for sh as shell not bash' (#907) from dboreham/fix-script-for-ubuntu into main
Reviewed-on: cerc-io/stack-orchestrator#907
2024-07-31 20:39:37 +00:00
dboreham 6c91b87348 Fix for sh as shell not bash 2024-07-31 14:30:53 -06:00
dboreham 7d18334953 Mainnet-laconic stack fixes for laconicd2 (#904)
Reviewed-on: cerc-io/stack-orchestrator#904
2024-07-31 13:51:28 +00:00
prathamesh 79c1c5ed99 Update fixturenet-laconicd stack to use alnt denom (#902)
Part of [laconicd testnet validator enrollment](https://www.notion.so/laconicd-testnet-validator-enrollment-6fc1d3cafcc64fef8c5ed3affa27c675)

Reviewed-on: cerc-io/stack-orchestrator#902
Reviewed-by: ashwin <ashwin@noreply.git.vdb.to>
Reviewed-by: David Boreham <dboreham@noreply.git.vdb.to>
Co-authored-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
Co-committed-by: Prathamesh Musale <prathamesh.musale0@gmail.com>
2024-07-31 13:27:54 +00:00
27 changed files with 171 additions and 383 deletions
@@ -1,57 +0,0 @@
name: Fixturenet-Eth-Plugeth-Arm-Test
on:
push:
branches: '*'
paths:
- '!**'
- '.gitea/workflows/triggers/fixturenet-eth-plugeth-arm-test'
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
- cron: '2 14 * * *'
jobs:
test:
name: "Run an Ethereum plugeth fixturenet test"
runs-on: ubuntu-latest-arm
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
# At present the stock setup-python action fails on Linux/aarch64
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: '3.8'
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: "Print Python version"
run: python3 --version
- name: "Install shiv"
run: pip install shiv
- name: "Generate build version file"
run: ./scripts/create_build_tag_file.sh
- name: "Build local shiv package"
run: ./scripts/build_shiv_package.sh
- name: "Run fixturenet-eth tests"
run: ./tests/fixturenet-eth-plugeth/run-test.sh
- name: Notify Vulcanize Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.VULCANIZE_SLACK_CI_ALERTS }}
- name: Notify DeepStack Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.DEEPSTACK_SLACK_CI_ALERTS }}
@@ -1,57 +0,0 @@
name: Fixturenet-Eth-Plugeth-Test
on:
push:
branches: '*'
paths:
- '!**'
- '.gitea/workflows/triggers/fixturenet-eth-plugeth-test'
schedule: # Note: coordinate with other tests to not overload runners at the same time of day
- cron: '2 14 * * *'
jobs:
test:
name: "Run an Ethereum plugeth fixturenet test"
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
# At present the stock setup-python action fails on Linux/aarch64
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: '3.8'
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: "Print Python version"
run: python3 --version
- name: "Install shiv"
run: pip install shiv
- name: "Generate build version file"
run: ./scripts/create_build_tag_file.sh
- name: "Build local shiv package"
run: ./scripts/build_shiv_package.sh
- name: "Run fixturenet-eth tests"
run: ./tests/fixturenet-eth-plugeth/run-test.sh
- name: Notify Vulcanize Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.VULCANIZE_SLACK_CI_ALERTS }}
- name: Notify DeepStack Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.DEEPSTACK_SLACK_CI_ALERTS }}
-55
View File
@@ -1,55 +0,0 @@
name: Fixturenet-Eth-Test
on:
push:
branches: '*'
paths:
- '!**'
- '.gitea/workflows/triggers/fixturenet-eth-test'
jobs:
test:
name: "Run an Ethereum fixturenet test"
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
# At present the stock setup-python action fails on Linux/aarch64
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: '3.8'
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: "Print Python version"
run: python3 --version
- name: "Install shiv"
run: pip install shiv
- name: "Generate build version file"
run: ./scripts/create_build_tag_file.sh
- name: "Build local shiv package"
run: ./scripts/build_shiv_package.sh
- name: "Run fixturenet-eth tests"
run: ./tests/fixturenet-eth/run-test.sh
- name: Notify Vulcanize Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.VULCANIZE_SLACK_CI_ALERTS }}
- name: Notify DeepStack Slack on CI failure
if: ${{ always() && github.ref_name == 'main' }}
uses: ravsamhq/notify-slack-action@v2
with:
status: ${{ job.status }}
notify_when: 'failure'
env:
SLACK_WEBHOOK_URL: ${{ secrets.DEEPSTACK_SLACK_CI_ALERTS }}
@@ -1,2 +0,0 @@
Change this file to trigger running the fixturenet-eth-plugeth-arm-test CI job
@@ -1,3 +0,0 @@
Change this file to trigger running the fixturenet-eth-plugeth-test CI job
trigger
trigger
@@ -1,2 +0,0 @@
Change this file to trigger running the fixturenet-eth-test CI job
@@ -7,3 +7,4 @@ Trigger
Trigger
Trigger
Trigger
Trigger
+1
View File
@@ -34,5 +34,6 @@ volumes_key = "volumes"
security_key = "security"
annotations_key = "annotations"
labels_key = "labels"
replicas_key = "replicas"
kind_config_filename = "kind-config.yml"
kube_config_filename = "kubeconfig.yml"
@@ -10,6 +10,7 @@ MONIKER="localtestnet"
KEYRING="test"
KEYALGO="secp256k1"
LOGLEVEL="${LOGLEVEL:-info}"
DENOM="alnt"
if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
@@ -33,7 +34,7 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
laconicd keys add $KEY --keyring-backend $KEYRING --algo $KEYALGO
# Set moniker and chain-id for Ethermint (Moniker can be anything, chain-id must be an integer)
laconicd init $MONIKER --chain-id $CHAINID --default-denom photon
laconicd init $MONIKER --chain-id $CHAINID --default-denom $DENOM
update_genesis() {
jq "$1" $HOME/.laconicd/config/genesis.json > $HOME/.laconicd/config/tmp_genesis.json &&
@@ -89,10 +90,12 @@ if [ "$1" == "clean" ] || [ ! -d "$HOME/.laconicd/data/blockstore.db" ]; then
fi
# Allocate genesis accounts (cosmos formatted addresses)
laconicd genesis add-genesis-account $KEY 100000000000000000000000000photon --keyring-backend $KEYRING
# 10^30 alnt | 10^12 lnt
laconicd genesis add-genesis-account $KEY 1000000000000000000000000000000$DENOM --keyring-backend $KEYRING
# Sign genesis transaction
laconicd genesis gentx $KEY 1000000000000000000000photon --keyring-backend $KEYRING --chain-id $CHAINID
# 10^24 alnt | 10^6 lnt
laconicd genesis gentx $KEY 1000000000000000000000000$DENOM --keyring-backend $KEYRING --chain-id $CHAINID
# Collect genesis tx
laconicd genesis collect-gentxs
@@ -107,7 +110,7 @@ fi
laconicd start \
--pruning=nothing \
--log_level $LOGLEVEL \
--minimum-gas-prices=0.0001photon \
--minimum-gas-prices=1$DENOM \
--api.enable \
--rpc.laddr="tcp://0.0.0.0:26657" \
--gql-server --gql-playground
@@ -6,4 +6,4 @@ services:
bondId:
chainId: laconic_9000-1
gas: 350000
fees: 200000photon
fees: 2000000alnt
@@ -6,4 +6,4 @@ services:
bondId:
chainId: laconic_9000-1
gas: 250000
fees: 200000photon
fees: 2000000alnt
@@ -1,5 +1,5 @@
#!/bin/sh
if [[ -n "$CERC_SCRIPT_DEBUG" ]]; then
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
@@ -9,7 +9,7 @@ LOGLEVEL="info"
laconicd start \
--pruning=nothing \
--log_level $LOGLEVEL \
--minimum-gas-prices=0.0001photon \
--minimum-gas-prices=1alnt \
--api.enable \
--gql-server \
--gql-playground
@@ -14,7 +14,7 @@ funds_balance=$(echo ${funds_response} | jq -r ".[0].balance[0].quantity")
echo "Balance is: ${funds_balance}"
# Create a bond
bond_create_result=$(${registry_command} bond create --type photon --quantity 1000000000)
bond_create_result=$(${registry_command} bond create --type alnt --quantity 1000000000)
bond_id=$(echo ${bond_create_result} | jq -r .bondId)
echo "Created bond with id: ${bond_id}"
@@ -7,16 +7,16 @@
"rpc": [
{"provider": "LX-tendermint-rpc", "address": "LACONIC_LACONICD_RPC_URL"}
],
"sdk_version": "0.45.1",
"sdk_version": "0.50.3",
"coin_type": "118",
"min_tx_fee": "800",
"addr_prefix": "ethm",
"addr_prefix": "laconic",
"logo": "/logos/cosmos.svg",
"assets": [{
"base": "photon",
"base": "alnt",
"symbol": "LNT",
"exponent": "6",
"coingecko_id": "cosmos",
"exponent": "18",
"coingecko_id": "cosmos",
"logo": "/logos/cosmos.svg"
}]
}
@@ -64,5 +64,6 @@ $ laconic-so --stack fixturenet-laconic-loaded deploy exec cli ./scripts/create-
Balance is: 99998999999999998999600000
Created bond with id: dd88e8d6f9567b32b28e70552aea4419c5dd3307ebae85a284d1fe38904e301a
Published demo-record-1.yml with id: bafyreierh3xnfivexlscdwubvczmddsnf46uytyfvrbdhkjzztvsz6ruly
...
```
The published record should be visible in the console.
The published records should be visible in the console.
@@ -30,4 +30,3 @@ config:
cli:
key: laconicd.mykey
address: laconicd.myaddress
@@ -22,7 +22,6 @@ from stack_orchestrator.opts import opts
from enum import Enum
from pathlib import Path
from shutil import copyfile, copytree
import json
import os
import sys
import tomli
@@ -34,8 +33,9 @@ default_spec_file_content = ""
class SetupPhase(Enum):
INITIALIZE = 1
JOIN = 2
CREATE = 3
ILLEGAL = 3
CONNECT = 3
CREATE = 4
ILLEGAL = 5
def _client_toml_path(network_dir: Path):
@@ -62,29 +62,13 @@ def _get_node_moniker_from_config(network_dir: Path):
return moniker
def _get_node_key_from_gentx(gentx_file_name: str):
gentx_file_path = Path(gentx_file_name)
if gentx_file_path.exists():
with open(Path(gentx_file_name), "rb") as f:
parsed_json = json.load(f)
return parsed_json['body']['messages'][0]['delegator_address']
else:
print(f"Error: gentx file: {gentx_file_name} does not exist")
sys.exit(1)
def _comma_delimited_to_list(list_str: str):
return list_str.split(",") if list_str else []
def _get_node_keys_from_gentx_files(gentx_file_list: str):
node_keys = []
gentx_files = _comma_delimited_to_list(gentx_file_list)
for gentx_file in gentx_files:
node_key = _get_node_key_from_gentx(gentx_file)
if node_key:
node_keys.append(node_key)
return node_keys
def _get_node_keys_from_gentx_files(gentx_address_list: str):
gentx_addresses = _comma_delimited_to_list(gentx_address_list)
return gentx_addresses
def _copy_gentx_files(network_dir: Path, gentx_file_list: str):
@@ -147,6 +131,34 @@ def _enable_cors(config_dir: Path):
output_file.write(app_file_content)
def _set_listen_address(config_dir: Path):
config_file_path = config_dir.joinpath("config.toml")
if not config_file_path.exists():
print("Error: config.toml not found")
sys.exit(1)
with open(config_file_path, "r") as input_file:
config_file_content = input_file.read()
existing_pattern = r'^pprof_laddr = "localhost:6060"'
replace_with = 'pprof_laddr = "0.0.0.0:6060"'
config_file_content = re.sub(existing_pattern, replace_with, config_file_content, flags=re.MULTILINE)
with open(config_file_path, "w") as output_file:
output_file.write(config_file_content)
app_file_path = config_dir.joinpath("app.toml")
if not app_file_path.exists():
print("Error: app.toml not found")
sys.exit(1)
with open(app_file_path, "r") as input_file:
app_file_content = input_file.read()
existing_pattern1 = r'^address = "tcp://localhost:1317"'
replace_with1 = 'address = "tcp://0.0.0.0:1317"'
app_file_content = re.sub(existing_pattern1, replace_with1, app_file_content, flags=re.MULTILINE)
existing_pattern2 = r'^address = "localhost:9090"'
replace_with2 = 'address = "0.0.0.0:9090"'
app_file_content = re.sub(existing_pattern2, replace_with2, app_file_content, flags=re.MULTILINE)
with open(app_file_path, "w") as output_file:
output_file.write(app_file_content)
def _phase_from_params(parameters):
phase = SetupPhase.ILLEGAL
if parameters.initialize_network:
@@ -171,6 +183,11 @@ def _phase_from_params(parameters):
print("Can't supply --initialize-network or --join-network with --create-network")
sys.exit(1)
phase = SetupPhase.CREATE
elif parameters.connect_network:
if parameters.initialize_network or parameters.join_network:
print("Can't supply --initialize-network or --join-network with --connect-network")
sys.exit(1)
phase = SetupPhase.CONNECT
return phase
@@ -178,7 +195,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
options = opts.o
currency = "stake" # Does this need to be a parameter?
currency = "alnt" # Does this need to be a parameter?
if options.debug:
print(f"parameters: {parameters}")
@@ -203,11 +220,12 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
output, status = run_container_command(
command_context,
"laconicd", f"laconicd init {parameters.node_moniker} --home {laconicd_home_path_in_container}\
--chain-id {parameters.chain_id}", mounts)
--chain-id {parameters.chain_id} --default-denom {currency}", mounts)
if options.debug:
print(f"Command output: {output}")
elif phase == SetupPhase.JOIN:
# In the join phase (alternative to connect) we are participating in a genesis ceremony for the chain
if not os.path.exists(network_dir):
print(f"Error: network directory {network_dir} doesn't exist")
sys.exit(1)
@@ -222,7 +240,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
output2, status2 = run_container_command(
command_context,
"laconicd",
f"laconicd add-genesis-account {parameters.key_name} 12900000000000000000000{currency}\
f"laconicd genesis add-genesis-account {parameters.key_name} 12900000000000000000000{currency}\
--home {laconicd_home_path_in_container} --keyring-backend test",
mounts)
if options.debug:
@@ -230,7 +248,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
output3, status3 = run_container_command(
command_context,
"laconicd",
f"laconicd gentx {parameters.key_name} 90000000000{currency} --home {laconicd_home_path_in_container}\
f"laconicd genesis gentx {parameters.key_name} 90000000000{currency} --home {laconicd_home_path_in_container}\
--chain-id {chain_id} --keyring-backend test",
mounts)
if options.debug:
@@ -240,7 +258,28 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
"laconicd",
f"laconicd keys show {parameters.key_name} -a --home {laconicd_home_path_in_container} --keyring-backend test",
mounts)
print(f"Node validator address: {output4}")
print(f"Node account address: {output4}")
elif phase == SetupPhase.CONNECT:
# In the connect phase (named to not conflict with join) we are making a node that syncs a chain with existing genesis.json
# but not with validator role. We need this kind of node in order to bootstrap it into a validator after it syncs
output1, status1 = run_container_command(
command_context, "laconicd", f"laconicd keys add {parameters.key_name} --home {laconicd_home_path_in_container}\
--keyring-backend test", mounts)
if options.debug:
print(f"Command output: {output1}")
output2, status2 = run_container_command(
command_context,
"laconicd",
f"laconicd keys show {parameters.key_name} -a --home {laconicd_home_path_in_container} --keyring-backend test",
mounts)
print(f"Node account address: {output2}")
output3, status3 = run_container_command(
command_context,
"laconicd",
f"laconicd cometbft show-validator --home {laconicd_home_path_in_container}",
mounts)
print(f"Node validator address: {output3}")
elif phase == SetupPhase.CREATE:
if not os.path.exists(network_dir):
@@ -259,15 +298,13 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
copyfile(genesis_file_path, os.path.join(network_dir, "config", os.path.basename(genesis_file_path)))
else:
# We're generating the genesis file
if not parameters.gentx_file_list:
print("Error: --gentx-files must be supplied")
sys.exit(1)
# First look in the supplied gentx files for the other nodes' keys
other_node_keys = _get_node_keys_from_gentx_files(parameters.gentx_file_list)
other_node_keys = _get_node_keys_from_gentx_files(parameters.gentx_address_list)
# Add those keys to our genesis, with balances we determine here (why?)
for other_node_key in other_node_keys:
outputk, statusk = run_container_command(
command_context, "laconicd", f"laconicd add-genesis-account {other_node_key} 12900000000000000000000{currency}\
command_context, "laconicd", f"laconicd genesis add-genesis-account {other_node_key} \
12900000000000000000000{currency}\
--home {laconicd_home_path_in_container} --keyring-backend test", mounts)
if options.debug:
print(f"Command output: {outputk}")
@@ -275,7 +312,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
_copy_gentx_files(network_dir, parameters.gentx_file_list)
# Now we can run collect-gentxs
output1, status1 = run_container_command(
command_context, "laconicd", f"laconicd collect-gentxs --home {laconicd_home_path_in_container}", mounts)
command_context, "laconicd", f"laconicd genesis collect-gentxs --home {laconicd_home_path_in_container}", mounts)
if options.debug:
print(f"Command output: {output1}")
print(f"Generated genesis file, please copy to other nodes as required: \
@@ -284,7 +321,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
_remove_persistent_peers(network_dir)
# In both cases we validate the genesis file now
output2, status1 = run_container_command(
command_context, "laconicd", f"laconicd validate-genesis --home {laconicd_home_path_in_container}", mounts)
command_context, "laconicd", f"laconicd genesis validate-genesis --home {laconicd_home_path_in_container}", mounts)
print(f"validate-genesis result: {output2}")
else:
@@ -319,6 +356,7 @@ def create(deployment_context: DeploymentContext, extra_args):
_insert_persistent_peers(deployment_config_dir, initial_persistent_peers)
# Enable CORS headers so explorers and so on can talk to the node
_enable_cors(deployment_config_dir)
_set_listen_address(deployment_config_dir)
# Copy the data directory contents into our deployment
# TODO: change this to work with non local paths
deployment_data_dir = deployment_context.deployment_dir.joinpath("data", "laconicd-data")
@@ -8,8 +8,11 @@ echo "Environment variables:"
env
# Test laconic stack
echo "Running laconic stack test"
# Bit of a hack, test the most recent package
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
if [ "$1" == "from-path" ]; then
TEST_TARGET_SO="laconic-so"
else
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
fi
# Set a non-default repo dir
export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir
echo "Testing this package: $TEST_TARGET_SO"
@@ -50,8 +50,10 @@ class LaconicStackSetupCommand:
key_name: str
initialize_network: bool
join_network: bool
connect_network: bool
create_network: bool
gentx_file_list: str
gentx_address_list: str
genesis_file: str
network_dir: str
+3 -2
View File
@@ -13,7 +13,6 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
import os
from typing import List, Any
from stack_orchestrator.deploy.deploy_types import DeployCommandContext, VolumeMapping
from stack_orchestrator.util import get_parsed_stack_config, get_yaml, get_pod_list, resolve_compose_file
@@ -83,7 +82,9 @@ def run_container_command(ctx: DeployCommandContext, service: str, command: str,
docker_output = deployer.run(
container_image,
["-c", command], entrypoint="sh",
user=f"{os.getuid()}:{os.getgid()}",
# Current laconicd container has a bug where it crashes when run not as root
# Commented out line below is a workaround. Created files end up owned by root on the host
# user=f"{os.getuid()}:{os.getgid()}",
volumes=docker_volumes
)
# There doesn't seem to be a way to get an exit code from docker.run()
+13 -4
View File
@@ -514,6 +514,13 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
os.mkdir(destination_script_dir)
script_paths = get_pod_script_paths(parsed_stack, pod)
_copy_files_to_directory(script_paths, destination_script_dir)
if parsed_spec.is_kubernetes_deployment():
for configmap in parsed_spec.get_configmaps():
source_config_dir = resolve_config_dir(stack_name, configmap)
if os.path.exists(source_config_dir):
destination_config_dir = deployment_dir_path.joinpath("configmaps", configmap)
copytree(source_config_dir, destination_config_dir, dirs_exist_ok=True)
# Delegate to the stack's Python code
# The deploy create command doesn't require a --stack argument so we need to insert the
# stack member here.
@@ -535,15 +542,17 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
@click.option("--chain-id", help="The new chain id")
@click.option("--key-name", help="Name for new node key")
@click.option("--gentx-files", help="List of comma-delimited gentx filenames from other nodes")
@click.option("--gentx-addresses", type=str, help="List of comma-delimited validator addresses for other nodes")
@click.option("--genesis-file", help="Genesis file for the network")
@click.option("--initialize-network", is_flag=True, default=False, help="Initialize phase")
@click.option("--join-network", is_flag=True, default=False, help="Join phase")
@click.option("--connect-network", is_flag=True, default=False, help="Connect phase")
@click.option("--create-network", is_flag=True, default=False, help="Create phase")
@click.option("--network-dir", help="Directory for network files")
@click.argument('extra_args', nargs=-1)
@click.pass_context
def setup(ctx, node_moniker, chain_id, key_name, gentx_files, genesis_file, initialize_network, join_network, create_network,
network_dir, extra_args):
parmeters = LaconicStackSetupCommand(chain_id, node_moniker, key_name, initialize_network, join_network, create_network,
gentx_files, genesis_file, network_dir)
def setup(ctx, node_moniker, chain_id, key_name, gentx_files, gentx_addresses, genesis_file, initialize_network, join_network,
connect_network, create_network, network_dir, extra_args):
parmeters = LaconicStackSetupCommand(chain_id, node_moniker, key_name, initialize_network, join_network, connect_network,
create_network, gentx_files, gentx_addresses, genesis_file, network_dir)
call_stack_deploy_setup(ctx.obj, parmeters, extra_args)
+33 -18
View File
@@ -78,28 +78,40 @@ class ClusterInfo:
if (opts.o.debug):
print(f"Env vars: {self.environment_variables.map}")
def get_nodeport(self):
def get_nodeports(self):
nodeports = []
for pod_name in self.parsed_pod_yaml_map:
pod = self.parsed_pod_yaml_map[pod_name]
services = pod["services"]
for service_name in services:
service_info = services[service_name]
if "ports" in service_info:
port = int(service_info["ports"][0])
if opts.o.debug:
print(f"service port: {port}")
service = client.V1Service(
metadata=client.V1ObjectMeta(name=f"{self.app_name}-nodeport"),
spec=client.V1ServiceSpec(
type="NodePort",
ports=[client.V1ServicePort(
port=port,
target_port=port
)],
selector={"app": self.app_name}
)
)
return service
for raw_port in service_info["ports"]:
if opts.o.debug:
print(f"service port: {raw_port}")
if ":" in raw_port:
parts = raw_port.split(":")
if len(parts) != 2:
raise Exception(f"Invalid port definition: {raw_port}")
node_port = int(parts[0])
pod_port = int(parts[1])
else:
node_port = None
pod_port = int(raw_port)
service = client.V1Service(
metadata=client.V1ObjectMeta(name=f"{self.app_name}-nodeport-{pod_port}"),
spec=client.V1ServiceSpec(
type="NodePort",
ports=[client.V1ServicePort(
port=pod_port,
target_port=pod_port,
node_port=node_port
)],
selector={"app": self.app_name}
)
)
nodeports.append(service)
return nodeports
def get_ingress(self, use_tls=False, certificate=None, cluster_issuer="letsencrypt-prod"):
# No ingress for a deployment that has no http-proxy defined, for now
@@ -373,9 +385,12 @@ class ClusterInfo:
spec=client.V1PodSpec(containers=containers, image_pull_secrets=image_pull_secrets, volumes=volumes),
)
spec = client.V1DeploymentSpec(
replicas=1, template=template, selector={
replicas=self.spec.get_replicas(),
template=template, selector={
"matchLabels":
{"app": self.app_name}})
{"app": self.app_name}
}
)
deployment = client.V1Deployment(
api_version="apps/v1",
+6 -5
View File
@@ -16,6 +16,7 @@ from datetime import datetime, timezone
from pathlib import Path
from kubernetes import client, config
from typing import List
from stack_orchestrator import constants
from stack_orchestrator.deploy.deployer import Deployer, DeployerConfigGenerator
@@ -246,8 +247,8 @@ class K8sDeployer(Deployer):
if opts.o.debug:
print("No ingress configured")
nodeport: client.V1Service = self.cluster_info.get_nodeport()
if nodeport:
nodeports: List[client.V1Service] = self.cluster_info.get_nodeports()
for nodeport in nodeports:
if opts.o.debug:
print(f"Sending this nodeport: {nodeport}")
if not opts.o.dry_run:
@@ -342,10 +343,10 @@ class K8sDeployer(Deployer):
if opts.o.debug:
print("No ingress to delete")
nodeport: client.V1Service = self.cluster_info.get_nodeport()
if nodeport:
nodeports: List[client.V1Service] = self.cluster_info.get_nodeports()
for nodeport in nodeports:
if opts.o.debug:
print(f"Deleting this nodeport: {ingress}")
print(f"Deleting this nodeport: {nodeport}")
try:
self.core_api.delete_namespaced_service(
namespace=self.k8s_namespace,
+3
View File
@@ -117,6 +117,9 @@ class Spec:
def get_annotations(self):
return self.obj.get(constants.annotations_key, {})
def get_replicas(self):
return self.obj.get(constants.replicas_key, 1)
def get_labels(self):
return self.obj.get(constants.labels_key, {})
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
set -e
echo "Running stack-orchestrator Ethereum plugeth fixturenet test"
# Bit of a hack, test the most recent package
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
CERC_STACK_NAME=fixturenet-plugeth-tx
# Set a new unique repo dir
export CERC_REPO_BASE_DIR=$(mktemp -d stack-orchestrator-fixturenet-eth-test.XXXXXXXXXX)
echo "Testing this package: $TEST_TARGET_SO"
echo "Test version command"
reported_version_string=$( $TEST_TARGET_SO version )
echo "Version reported is: ${reported_version_string}"
echo "Cloning repositories into: $CERC_REPO_BASE_DIR"
$TEST_TARGET_SO --stack $CERC_STACK_NAME setup-repositories
echo "Building containers"
$TEST_TARGET_SO --stack $CERC_STACK_NAME build-containers
echo "Images in registry:"
docker image ls
echo "Deploying the cluster"
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy up
# Verify that the fixturenet is up and running
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy ps
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy exec fixturenet-eth-bootnode-lighthouse /scripts/status-internal.sh
initial_block_number=$($TEST_TARGET_SO --stack fixturenet-plugeth-tx deploy exec foundry "cast block-number")
# Check that the block number increases some time later
sleep 12
subsequent_block_number=$($TEST_TARGET_SO --stack $CERC_STACK_NAME deploy exec foundry "cast block-number")
block_number_difference=$((subsequent_block_number - initial_block_number))
# Block height difference should be between 1 and some small number
if [[ $block_number_difference -gt 1 && $block_number_difference -lt 10 ]]; then
echo "Test passed"
test_result=0
else
echo "Test failed: block numbers were ${initial_block_number} and ${subsequent_block_number}"
test_result=1
fi
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy down
echo "Removing cloned repositories"
rm -rf $CERC_REPO_BASE_DIR
exit $test_result
-80
View File
@@ -1,80 +0,0 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
echo "$(date +"%Y-%m-%d %T"): Running stack-orchestrator Ethereum fixturenet test"
# Bit of a hack, test the most recent package
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
# Set a new unique repo dir
export CERC_REPO_BASE_DIR=$(mktemp -d stack-orchestrator-fixturenet-eth-test.XXXXXXXXXX)
echo "$(date +"%Y-%m-%d %T"): Testing this package: $TEST_TARGET_SO"
echo "$(date +"%Y-%m-%d %T"): Test version command"
reported_version_string=$( $TEST_TARGET_SO version )
echo "$(date +"%Y-%m-%d %T"): Version reported is: ${reported_version_string}"
echo "$(date +"%Y-%m-%d %T"): Cloning repositories into: $CERC_REPO_BASE_DIR"
$TEST_TARGET_SO --stack fixturenet-eth setup-repositories
echo "$(date +"%Y-%m-%d %T"): Building containers"
$TEST_TARGET_SO --stack fixturenet-eth build-containers
echo "$(date +"%Y-%m-%d %T"): Starting stack"
$TEST_TARGET_SO --stack fixturenet-eth deploy up
echo "$(date +"%Y-%m-%d %T"): Stack started"
# Verify that the fixturenet is up and running
$TEST_TARGET_SO --stack fixturenet-eth deploy ps
# echo "$(date +"%Y-%m-%d %T"): Getting stack status"
# $TEST_TARGET_SO --stack fixturenet-eth deploy exec fixturenet-eth-bootnode-lighthouse /scripts/status-internal.sh
timeout=900 # 15 minutes
echo "$(date +"%Y-%m-%d %T"): Getting initial block number. Timeout set to $timeout seconds"
start_time=$(date +%s)
elapsed_time=0
initial_block_number=0
while [ "$initial_block_number" -eq 0 ] && [ $elapsed_time -lt $timeout ]; do
sleep 10
echo "$(date +"%Y-%m-%d %T"): Waiting for initial block..."
initial_block_number=$($TEST_TARGET_SO --stack fixturenet-eth deploy exec foundry "cast block-number")
current_time=$(date +%s)
elapsed_time=$((current_time - start_time))
done
subsequent_block_number=$initial_block_number
# if initial block was 0 after timeout, assume chain did not start successfully and skip finding subsequent block
if [[ $initial_block_number -gt 0 ]]; then
timeout=300
echo "$(date +"%Y-%m-%d %T"): Getting subsequent block number. Timeout set to $timeout seconds"
start_time=$(date +%s)
elapsed_time=0
# wait for 5 blocks or timeout
while [ "$subsequent_block_number" -le $((initial_block_number + 5)) ] && [ $elapsed_time -lt $timeout ]; do
sleep 10
echo "$(date +"%Y-%m-%d %T"): Waiting for five blocks or $timeout seconds..."
subsequent_block_number=$($TEST_TARGET_SO --stack fixturenet-eth deploy exec foundry "cast block-number")
current_time=$(date +%s)
elapsed_time=$((current_time - start_time))
done
fi
# will return 0 if either of the above loops timed out
block_number_difference=$((subsequent_block_number - initial_block_number))
echo "$(date +"%Y-%m-%d %T"): Results of block height queries:"
echo "Initial block height: $initial_block_number"
echo "Subsequent block height: $subsequent_block_number"
# Block height difference should be between 1 and some small number
if [[ $block_number_difference -gt 1 && $block_number_difference -lt 100 ]]; then
echo "Test passed"
test_result=0
else
echo "Test failed: block numbers were ${initial_block_number} and ${subsequent_block_number}"
echo "Logs from stack:"
$TEST_TARGET_SO --stack fixturenet-eth deploy logs
test_result=1
fi
$TEST_TARGET_SO --stack fixturenet-eth deploy down --delete-volumes
echo "$(date +"%Y-%m-%d %T"): Removing cloned repositories"
rm -rf $CERC_REPO_BASE_DIR
echo "$(date +"%Y-%m-%d %T"): Test finished"
exit $test_result
+13 -2
View File
@@ -4,6 +4,10 @@ if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
set_ownership () {
sudo chown $USER: -R $1
}
node_count=4
node_dir_prefix="laconic-network-dir"
chain_id="laconic_81337-6"
@@ -15,7 +19,7 @@ do
node_network_dir=${node_dir_prefix}${i}
if [[ -d $node_network_dir ]]; then
echo "Deleting ${node_network_dir}"
rm -rf ${node_network_dir}
sudo rm -rf ${node_network_dir}
fi
done
echo "Deleting any existing deployments..."
@@ -39,6 +43,7 @@ do
node_network_dir=${node_dir_prefix}${i}
node_moniker=${node_moniker_prefix}${i}
laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_network_dir} --initialize-network --chain-id ${chain_id} --node-moniker ${node_moniker}
set_ownership ${node_network_dir}
done
echo "Joining ${node_count} nodes to the network..."
@@ -47,6 +52,7 @@ do
node_network_dir=${node_dir_prefix}${i}
node_moniker=${node_moniker_prefix}${i}
laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_network_dir} --join-network --key-name ${node_moniker}
set_ownership ${node_network_dir}
done
echo "Merging ${node_count} nodes genesis txns..."
@@ -57,11 +63,15 @@ for (( i=2 ; i<=$node_count ; i++ ));
do
node_network_dir=${node_dir_prefix}${i}
node_gentx_file=$(ls ${node_network_dir}/config/gentx/*.json)
node_gentx_address=$(grep address ${node_network_dir}/config/genesis.json | head -1 | cut -d '"' -f 4)
gentx_files+=${delimeter}${node_gentx_file}
gentx_addresses+=${delimeter}${node_gentx_address}
delimeter=","
done
echo "gentx files:"
echo ${gentx_files}
# Generate the genesis file on node 1
laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_dir_prefix}1 --create-network --gentx-files ${gentx_files}
laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_dir_prefix}1 --create-network --gentx-files ${gentx_files} --gentx-addresses ${gentx_addresses}
genesis_file=${node_dir_prefix}1/config/genesis.json
# Now import the genesis file to the other nodes
for (( i=2 ; i<=$node_count ; i++ ));
@@ -69,6 +79,7 @@ do
echo "Importing genesis.json into node ${i}"
node_network_dir=${node_dir_prefix}${i}
laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_network_dir} --create-network --genesis-file ${genesis_file}
set_ownership ${node_network_dir}
done
# Create deployments