Compare commits

..

1 Commits

Author SHA1 Message Date
3ba9436863 Add git to webapp base container. 2024-06-24 23:57:15 -05:00
29 changed files with 117 additions and 361 deletions

View File

@ -4,11 +4,9 @@ with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read() long_description = fh.read()
with open("requirements.txt", "r", encoding="utf-8") as fh: with open("requirements.txt", "r", encoding="utf-8") as fh:
requirements = fh.read() requirements = fh.read()
with open("stack_orchestrator/data/version.txt", "r", encoding="utf-8") as fh:
version = fh.readlines()[-1].strip(" \n")
setup( setup(
name='laconic-stack-orchestrator', name='laconic-stack-orchestrator',
version=version, version='1.0.12',
author='Cerc', author='Cerc',
author_email='info@cerc.io', author_email='info@cerc.io',
license='GNU Affero General Public License', license='GNU Affero General Public License',

View File

@ -21,6 +21,11 @@ from stack_orchestrator.util import get_parsed_stack_config, warn_exit
def get_containers_in_scope(stack: str): def get_containers_in_scope(stack: str):
# See: https://stackoverflow.com/a/20885799/1701505
from stack_orchestrator import data
with importlib.resources.open_text(data, "container-image-list.txt") as container_list_file:
all_containers = container_list_file.read().splitlines()
containers_in_scope = [] containers_in_scope = []
if stack: if stack:
stack_config = get_parsed_stack_config(stack) stack_config = get_parsed_stack_config(stack)
@ -28,14 +33,11 @@ def get_containers_in_scope(stack: str):
warn_exit(f"stack {stack} does not define any containers") warn_exit(f"stack {stack} does not define any containers")
containers_in_scope = stack_config['containers'] containers_in_scope = stack_config['containers']
else: else:
# See: https://stackoverflow.com/a/20885799/1701505 containers_in_scope = all_containers
from stack_orchestrator import data
with importlib.resources.open_text(data, "container-image-list.txt") as container_list_file:
containers_in_scope = container_list_file.read().splitlines()
if opts.o.verbose: if opts.o.verbose:
print(f'Containers: {containers_in_scope}') print(f'Containers: {containers_in_scope}')
if stack: if stack:
print(f"Stack: {stack}") print(f"Stack: {stack}")
return containers_in_scope return containers_in_scope

View File

@ -1,10 +0,0 @@
services:
laconic-explorer:
restart: unless-stopped
image: cerc/ping-pub:local
environment:
- LACONIC_LACONICD_API_URL=${LACONIC_LACONICD_API_URL:-http://localhost:1317}
- LACONIC_LACONICD_RPC_URL=${LACONIC_LACONICD_RPC_URL:-http://localhost:26657}
- LACONIC_LACONICD_CHAIN_ID=${LACONIC_LACONICD_CHAIN_ID:-chain-id-not-set}
ports:
- "5173"

View File

@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build cerc/laconic-console-host # Build cerc/laconic-registry-cli
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh source ${CERC_CONTAINER_BASE_DIR}/build-base.sh

View File

@ -28,8 +28,6 @@ RUN \
&& su ${USERNAME} -c "umask 0002 && npm install -g semver" \ && su ${USERNAME} -c "umask 0002 && npm install -g semver" \
# Install pnpm # Install pnpm
&& su ${USERNAME} -c "umask 0002 && npm install -g pnpm" \ && su ${USERNAME} -c "umask 0002 && npm install -g pnpm" \
# Install bun
&& su ${USERNAME} -c "umask 0002 && npm install -g bun@1.1.x" \
&& npm cache clean --force > /dev/null 2>&1 && npm cache clean --force > /dev/null 2>&1
# [Optional] Uncomment this section to install additional OS packages. # [Optional] Uncomment this section to install additional OS packages.

View File

@ -14,8 +14,6 @@ if [ -z "$CERC_BUILD_TOOL" ]; then
CERC_BUILD_TOOL=pnpm CERC_BUILD_TOOL=pnpm
elif [ -f "yarn.lock" ]; then elif [ -f "yarn.lock" ]; then
CERC_BUILD_TOOL=yarn CERC_BUILD_TOOL=yarn
elif [ -f "bun.lockb" ]; then
CERC_BUILD_TOOL=bun
else else
CERC_BUILD_TOOL=npm CERC_BUILD_TOOL=npm
fi fi

View File

@ -13,8 +13,6 @@ if [ -z "$CERC_BUILD_TOOL" ]; then
CERC_BUILD_TOOL=pnpm CERC_BUILD_TOOL=pnpm
elif [ -f "yarn.lock" ]; then elif [ -f "yarn.lock" ]; then
CERC_BUILD_TOOL=yarn CERC_BUILD_TOOL=yarn
elif [ -f "bun.lockb" ]; then
CERC_BUILD_TOOL=bun
else else
CERC_BUILD_TOOL=npm CERC_BUILD_TOOL=npm
fi fi

View File

@ -5,7 +5,7 @@ fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
CERC_MAX_GENERATE_TIME=${CERC_MAX_GENERATE_TIME:-120} CERC_MAX_GENERATE_TIME=${CERC_MAX_GENERATE_TIME:-60}
tpid="" tpid=""
ctrl_c() { ctrl_c() {
@ -20,8 +20,6 @@ if [ -z "$CERC_BUILD_TOOL" ]; then
CERC_BUILD_TOOL=pnpm CERC_BUILD_TOOL=pnpm
elif [ -f "yarn.lock" ]; then elif [ -f "yarn.lock" ]; then
CERC_BUILD_TOOL=yarn CERC_BUILD_TOOL=yarn
elif [ -f "bun.lockb" ]; then
CERC_BUILD_TOOL=bun
else else
CERC_BUILD_TOOL=npm CERC_BUILD_TOOL=npm
fi fi

View File

@ -1,10 +0,0 @@
FROM cerc/ping-pub-base:local
COPY ./scripts/update-explorer-config.sh /scripts
COPY ./scripts/start-serving-explorer.sh /scripts
COPY ./config/laconic-chaindata-template.json /config/chains/laconic-chaindata-template.json
EXPOSE 5173
WORKDIR /app
CMD ["/scripts/start-serving-explorer.sh"]

View File

@ -1,8 +0,0 @@
FROM cerc/webapp-base:local
WORKDIR /app
COPY . .
RUN yarn

View File

@ -1,8 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Build the ping pub image # Build the ping pub image
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# Two-stage build is to allow us to pick up both the upstream repo's files, and local files here for config docker build -t cerc/ping-pub:local ${build_command_args} -f $CERC_REPO_BASE_DIR/explorer/Dockerfile $CERC_REPO_BASE_DIR/explorer
docker build -t cerc/ping-pub-base:local ${build_command_args} -f $SCRIPT_DIR/Dockerfile.base $CERC_REPO_BASE_DIR/explorer
docker build -t cerc/ping-pub:local ${build_command_args} -f $SCRIPT_DIR/Dockerfile $SCRIPT_DIR

View File

@ -1,22 +0,0 @@
{
"chain_name": "LACONIC_LACONICD_CHAIN_ID",
"registry_name": "LACONIC_LACONICD_CHAIN_ID",
"api": [
{"provider": "LX-one-tree-one-seven", "address": "LACONIC_LACONICD_API_URL"}
],
"rpc": [
{"provider": "LX-tendermint-rpc", "address": "LACONIC_LACONICD_RPC_URL"}
],
"sdk_version": "0.45.1",
"coin_type": "118",
"min_tx_fee": "800",
"addr_prefix": "ethm",
"logo": "/logos/cosmos.svg",
"assets": [{
"base": "aphoton",
"symbol": "LNT",
"exponent": "6",
"coingecko_id": "cosmos",
"logo": "/logos/cosmos.svg"
}]
}

View File

@ -1,13 +0,0 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
${SCRIPT_DIR}/update-explorer-config.sh
echo "Starting serving explorer"
# Force cache re-build because vite is dumb and can't be restarted otherwise
yarn serve --host --force

View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -e
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x
fi
# Verify that we have the config variables we need
if [[ -z ${LACONIC_LACONICD_API_URL} ]]; then
echo "Error: LACONIC_LACONICD_API_URL not defined"
exit 1
fi
if [[ -z ${LACONIC_LACONICD_RPC_URL} ]]; then
echo "Error: LACONIC_LACONICD_RPC_URL not defined"
exit 1
fi
if [[ -z ${LACONIC_LACONICD_CHAIN_ID} ]]; then
echo "Error: LACONIC_LACONICD_CHAIN_ID not defined"
exit 1
fi
# Ping-pub explorer has endlessly confusing behavior where it
# infers the directory from which to load chain configuration files
# by the presence or absense of the substring "testnet" in the host name
# (browser side -- the host name of the host in the address bar of the browser)
# Accordingly we configure our network in both directories in order to
# subvert this lunacy.
explorer_mainnet_config_dir=/app/chains/mainnet
explorer_testnet_config_dir=/app/chains/testnet
config_template_file=/config/chains/laconic-chaindata-template.json
chain_config_name=laconic.json
mainnet_config_file=${explorer_mainnet_config_dir}/${chain_config_name}
testnet_config_file=${explorer_testnet_config_dir}/${chain_config_name}
# Delete the stock config files
rm -f ${explorer_testnet_config_dir}/*
rm -f ${explorer_mainnet_config_dir}/*
# Copy in our template file
cp ${config_template_file} ${mainnet_config_file}
# Update the file with the config variables
sed -i "s#LACONIC_LACONICD_API_URL#${LACONIC_LACONICD_API_URL}#g" ${mainnet_config_file}
sed -i "s#LACONIC_LACONICD_RPC_URL#${LACONIC_LACONICD_RPC_URL}#g" ${mainnet_config_file}
sed -i "s#LACONIC_LACONICD_CHAIN_ID#${LACONIC_LACONICD_CHAIN_ID}#g" ${mainnet_config_file}
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
echo "Updated chaindata file:"
cat ${mainnet_config_file}
fi
# Copy over to the testnet directory
cp ${mainnet_config_file} ${testnet_config_file}

View File

@ -28,8 +28,6 @@ RUN \
&& su ${USERNAME} -c "umask 0002 && npm install -g semver" \ && su ${USERNAME} -c "umask 0002 && npm install -g semver" \
# Install pnpm # Install pnpm
&& su ${USERNAME} -c "umask 0002 && npm install -g pnpm" \ && su ${USERNAME} -c "umask 0002 && npm install -g pnpm" \
# Install bun
&& su ${USERNAME} -c "umask 0002 && npm install -g bun@1.1.x" \
&& npm cache clean --force > /dev/null 2>&1 && npm cache clean --force > /dev/null 2>&1
# [Optional] Uncomment this section to install additional OS packages. # [Optional] Uncomment this section to install additional OS packages.

View File

@ -4,8 +4,6 @@ if [ -n "$CERC_SCRIPT_DEBUG" ]; then
set -x set -x
fi fi
# TODO: document what this script does
WORK_DIR="${1:-./}" WORK_DIR="${1:-./}"
cd "${WORK_DIR}" || exit 1 cd "${WORK_DIR}" || exit 1

View File

@ -27,8 +27,6 @@ elif [ -f "${WORK_DIR}/package.json" ]; then
CERC_BUILD_TOOL=pnpm CERC_BUILD_TOOL=pnpm
elif [ -f "yarn.lock" ]; then elif [ -f "yarn.lock" ]; then
CERC_BUILD_TOOL=yarn CERC_BUILD_TOOL=yarn
elif [ -f "bun.lockb" ]; then
CERC_BUILD_TOOL=bun
else else
CERC_BUILD_TOOL=npm CERC_BUILD_TOOL=npm
fi fi

View File

@ -18,7 +18,7 @@ from stack_orchestrator.deploy.deploy_types import DeployCommandContext, Laconic
from stack_orchestrator.deploy.deployment_context import DeploymentContext from stack_orchestrator.deploy.deployment_context import DeploymentContext
from stack_orchestrator.deploy.stack_state import State from stack_orchestrator.deploy.stack_state import State
from stack_orchestrator.deploy.deploy_util import VolumeMapping, run_container_command from stack_orchestrator.deploy.deploy_util import VolumeMapping, run_container_command
from stack_orchestrator.opts import opts from stack_orchestrator.command_types import CommandOptions
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
from shutil import copyfile, copytree from shutil import copyfile, copytree
@ -62,7 +62,7 @@ def _get_node_moniker_from_config(network_dir: Path):
return moniker return moniker
def _get_node_key_from_gentx(gentx_file_name: str): def _get_node_key_from_gentx(options: CommandOptions, gentx_file_name: str):
gentx_file_path = Path(gentx_file_name) gentx_file_path = Path(gentx_file_name)
if gentx_file_path.exists(): if gentx_file_path.exists():
with open(Path(gentx_file_name), "rb") as f: with open(Path(gentx_file_name), "rb") as f:
@ -77,24 +77,24 @@ def _comma_delimited_to_list(list_str: str):
return list_str.split(",") if list_str else [] return list_str.split(",") if list_str else []
def _get_node_keys_from_gentx_files(gentx_file_list: str): def _get_node_keys_from_gentx_files(options: CommandOptions, gentx_file_list: str):
node_keys = [] node_keys = []
gentx_files = _comma_delimited_to_list(gentx_file_list) gentx_files = _comma_delimited_to_list(gentx_file_list)
for gentx_file in gentx_files: for gentx_file in gentx_files:
node_key = _get_node_key_from_gentx(gentx_file) node_key = _get_node_key_from_gentx(options, gentx_file)
if node_key: if node_key:
node_keys.append(node_key) node_keys.append(node_key)
return node_keys return node_keys
def _copy_gentx_files(network_dir: Path, gentx_file_list: str): def _copy_gentx_files(options: CommandOptions, network_dir: Path, gentx_file_list: str):
gentx_files = _comma_delimited_to_list(gentx_file_list) gentx_files = _comma_delimited_to_list(gentx_file_list)
for gentx_file in gentx_files: for gentx_file in gentx_files:
gentx_file_path = Path(gentx_file) gentx_file_path = Path(gentx_file)
copyfile(gentx_file_path, os.path.join(network_dir, "config", "gentx", os.path.basename(gentx_file_path))) copyfile(gentx_file_path, os.path.join(network_dir, "config", "gentx", os.path.basename(gentx_file_path)))
def _remove_persistent_peers(network_dir: Path): def _remove_persistent_peers(options: CommandOptions, network_dir: Path):
config_file_path = _config_toml_path(network_dir) config_file_path = _config_toml_path(network_dir)
if not config_file_path.exists(): if not config_file_path.exists():
print("Error: config.toml not found") print("Error: config.toml not found")
@ -108,45 +108,20 @@ def _remove_persistent_peers(network_dir: Path):
output_file.write(config_file_content) output_file.write(config_file_content)
def _insert_persistent_peers(config_dir: Path, new_persistent_peers: str): def _insert_persistent_peers(options: CommandOptions, config_dir: Path, new_persistent_peers: str):
config_file_path = config_dir.joinpath("config.toml") config_file_path = config_dir.joinpath("config.toml")
if not config_file_path.exists(): if not config_file_path.exists():
print("Error: config.toml not found") print("Error: config.toml not found")
sys.exit(1) sys.exit(1)
with open(config_file_path, "r") as input_file: with open(config_file_path, "r") as input_file:
config_file_content = input_file.read() config_file_content = input_file.read()
persistent_peers_pattern = r'^persistent_peers = ""' persistent_peers_pattern = '^persistent_peers = ""'
replace_with = f"persistent_peers = \"{new_persistent_peers}\"" replace_with = f"persistent_peers = \"{new_persistent_peers}\""
config_file_content = re.sub(persistent_peers_pattern, replace_with, config_file_content, flags=re.MULTILINE) config_file_content = re.sub(persistent_peers_pattern, replace_with, config_file_content, flags=re.MULTILINE)
with open(config_file_path, "w") as output_file: with open(config_file_path, "w") as output_file:
output_file.write(config_file_content) output_file.write(config_file_content)
def _enable_cors(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()
cors_pattern = r'^cors_allowed_origins = \[]'
replace_with = 'cors_allowed_origins = ["*"]'
config_file_content = re.sub(cors_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()
cors_pattern = r'^enabled-unsafe-cors = false'
replace_with = "enabled-unsafe-cors = true"
app_file_content = re.sub(cors_pattern, replace_with, 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): def _phase_from_params(parameters):
phase = SetupPhase.ILLEGAL phase = SetupPhase.ILLEGAL
if parameters.initialize_network: if parameters.initialize_network:
@ -176,7 +151,7 @@ def _phase_from_params(parameters):
def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCommand, extra_args): def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCommand, extra_args):
options = opts.o options = command_context.cluster_context.options
currency = "stake" # Does this need to be a parameter? currency = "stake" # Does this need to be a parameter?
@ -263,7 +238,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
print("Error: --gentx-files must be supplied") print("Error: --gentx-files must be supplied")
sys.exit(1) sys.exit(1)
# First look in the supplied gentx files for the other nodes' keys # 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(options, parameters.gentx_file_list)
# Add those keys to our genesis, with balances we determine here (why?) # Add those keys to our genesis, with balances we determine here (why?)
for other_node_key in other_node_keys: for other_node_key in other_node_keys:
outputk, statusk = run_container_command( outputk, statusk = run_container_command(
@ -272,7 +247,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
if options.debug: if options.debug:
print(f"Command output: {outputk}") print(f"Command output: {outputk}")
# Copy the gentx json files into our network dir # Copy the gentx json files into our network dir
_copy_gentx_files(network_dir, parameters.gentx_file_list) _copy_gentx_files(options, network_dir, parameters.gentx_file_list)
# Now we can run collect-gentxs # Now we can run collect-gentxs
output1, status1 = run_container_command( output1, status1 = run_container_command(
command_context, "laconicd", f"laconicd collect-gentxs --home {laconicd_home_path_in_container}", mounts) command_context, "laconicd", f"laconicd collect-gentxs --home {laconicd_home_path_in_container}", mounts)
@ -281,7 +256,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
print(f"Generated genesis file, please copy to other nodes as required: \ print(f"Generated genesis file, please copy to other nodes as required: \
{os.path.join(network_dir, 'config', 'genesis.json')}") {os.path.join(network_dir, 'config', 'genesis.json')}")
# Last thing, collect-gentxs puts a likely bogus set of persistent_peers in config.toml so we remove that now # Last thing, collect-gentxs puts a likely bogus set of persistent_peers in config.toml so we remove that now
_remove_persistent_peers(network_dir) _remove_persistent_peers(options, network_dir)
# In both cases we validate the genesis file now # In both cases we validate the genesis file now
output2, status1 = run_container_command( output2, status1 = run_container_command(
command_context, "laconicd", f"laconicd validate-genesis --home {laconicd_home_path_in_container}", mounts) command_context, "laconicd", f"laconicd validate-genesis --home {laconicd_home_path_in_container}", mounts)
@ -292,7 +267,7 @@ def setup(command_context: DeployCommandContext, parameters: LaconicStackSetupCo
sys.exit(1) sys.exit(1)
def create(deployment_context: DeploymentContext, extra_args): def create(context: DeploymentContext, extra_args):
network_dir = extra_args[0] network_dir = extra_args[0]
if network_dir is None: if network_dir is None:
print("Error: --network-dir must be supplied") print("Error: --network-dir must be supplied")
@ -311,17 +286,15 @@ def create(deployment_context: DeploymentContext, extra_args):
sys.exit(1) sys.exit(1)
# Copy the network directory contents into our deployment # Copy the network directory contents into our deployment
# TODO: change this to work with non local paths # TODO: change this to work with non local paths
deployment_config_dir = deployment_context.deployment_dir.joinpath("data", "laconicd-config") deployment_config_dir = context.deployment_dir.joinpath("data", "laconicd-config")
copytree(config_dir_path, deployment_config_dir, dirs_exist_ok=True) copytree(config_dir_path, deployment_config_dir, dirs_exist_ok=True)
# If supplied, add the initial persistent peers to the config file # If supplied, add the initial persistent peers to the config file
if extra_args[1]: if extra_args[1]:
initial_persistent_peers = extra_args[1] initial_persistent_peers = extra_args[1]
_insert_persistent_peers(deployment_config_dir, initial_persistent_peers) _insert_persistent_peers(context.command_context.cluster_context.options, deployment_config_dir, initial_persistent_peers)
# Enable CORS headers so explorers and so on can talk to the node
_enable_cors(deployment_config_dir)
# Copy the data directory contents into our deployment # Copy the data directory contents into our deployment
# TODO: change this to work with non local paths # TODO: change this to work with non local paths
deployment_data_dir = deployment_context.deployment_dir.joinpath("data", "laconicd-data") deployment_data_dir = context.deployment_dir.joinpath("data", "laconicd-data")
copytree(data_dir_path, deployment_data_dir, dirs_exist_ok=True) copytree(data_dir_path, deployment_data_dir, dirs_exist_ok=True)

View File

@ -2,15 +2,14 @@ version: "1.0"
name: mainnet-laconic name: mainnet-laconic
description: "Mainnet laconic node" description: "Mainnet laconic node"
repos: repos:
- git.vdb.to/cerc-io/laconicd - cerc-io/laconicd
- github.com/lirewine/debug - lirewine/debug
- github.com/lirewine/crypto - lirewine/crypto
- github.com/lirewine/gem - lirewine/gem
- github.com/lirewine/sdk - lirewine/sdk
- git.vdb.to/cerc-io/laconic-sdk - cerc-io/laconic-sdk
- git.vdb.to/cerc-io/laconic-registry-cli - cerc-io/laconic-registry-cli
- git.vdb.to/cerc-io/laconic-console - cerc-io/laconic-console
- github.com/ping-pub/explorer
npms: npms:
- laconic-sdk - laconic-sdk
- laconic-registry-cli - laconic-registry-cli
@ -24,8 +23,7 @@ containers:
- cerc/laconic-registry-cli - cerc/laconic-registry-cli
- cerc/webapp-base - cerc/webapp-base
- cerc/laconic-console-host - cerc/laconic-console-host
- cerc/ping-pub
pods: pods:
- mainnet-laconicd - mainnet-laconicd
- fixturenet-laconic-console - fixturenet-laconic-console
- laconic-explorer

View File

@ -26,15 +26,8 @@ import click
from pathlib import Path from pathlib import Path
from stack_orchestrator import constants from stack_orchestrator import constants
from stack_orchestrator.opts import opts from stack_orchestrator.opts import opts
from stack_orchestrator.util import ( from stack_orchestrator.util import include_exclude_check, get_parsed_stack_config, global_options2, get_dev_root_path
get_stack_path, from stack_orchestrator.util import resolve_compose_file
include_exclude_check,
get_parsed_stack_config,
global_options2,
get_dev_root_path,
stack_is_in_deployment,
resolve_compose_file,
)
from stack_orchestrator.deploy.deployer import Deployer, DeployerException from stack_orchestrator.deploy.deployer import Deployer, DeployerException
from stack_orchestrator.deploy.deployer_factory import getDeployer from stack_orchestrator.deploy.deployer_factory import getDeployer
from stack_orchestrator.deploy.deploy_types import ClusterContext, DeployCommandContext from stack_orchestrator.deploy.deploy_types import ClusterContext, DeployCommandContext
@ -67,7 +60,6 @@ def command(ctx, include, exclude, env_file, cluster, deploy_to):
if deploy_to is None: if deploy_to is None:
deploy_to = "compose" deploy_to = "compose"
stack = get_stack_path(stack)
ctx.obj = create_deploy_context(global_options2(ctx), None, stack, include, exclude, cluster, env_file, deploy_to) ctx.obj = create_deploy_context(global_options2(ctx), None, stack, include, exclude, cluster, env_file, deploy_to)
# Subcommand is executed now, by the magic of click # Subcommand is executed now, by the magic of click
@ -282,12 +274,16 @@ def _make_default_cluster_name(deployment, compose_dir, stack, include, exclude)
# stack has to be either PathLike pointing to a stack yml file, or a string with the name of a known stack # stack has to be either PathLike pointing to a stack yml file, or a string with the name of a known stack
def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file): def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
dev_root_path = get_dev_root_path(ctx) dev_root_path = get_dev_root_path(ctx)
# TODO: hack, this should be encapsulated by the deployment context. # TODO: huge hack, fix this
deployment = stack_is_in_deployment(stack) # If the caller passed a path for the stack file, then we know that we can get the compose files
if deployment: # from the same directory
compose_dir = stack.joinpath("compose") deployment = False
if isinstance(stack, os.PathLike):
compose_dir = stack.parent.joinpath("compose")
deployment = True
else: else:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure # See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
compose_dir = Path(__file__).absolute().parent.parent.joinpath("data", "compose") compose_dir = Path(__file__).absolute().parent.parent.joinpath("data", "compose")

View File

@ -50,15 +50,15 @@ def command(ctx, dir):
def make_deploy_context(ctx) -> DeployCommandContext: def make_deploy_context(ctx) -> DeployCommandContext:
context: DeploymentContext = ctx.obj context: DeploymentContext = ctx.obj
stack_file_path = context.get_stack_file()
env_file = context.get_env_file() env_file = context.get_env_file()
cluster_name = context.get_cluster_id() cluster_name = context.get_cluster_id()
if constants.deploy_to_key in context.spec.obj: if constants.deploy_to_key in context.spec.obj:
deployment_type = context.spec.obj[constants.deploy_to_key] deployment_type = context.spec.obj[constants.deploy_to_key]
else: else:
deployment_type = constants.compose_deploy_type deployment_type = constants.compose_deploy_type
stack = context.deployment_dir return create_deploy_context(ctx.parent.parent.obj, context, stack_file_path, None, None, cluster_name, env_file,
return create_deploy_context(ctx.parent.parent.obj, context, stack, None, None, deployment_type)
cluster_name, env_file, deployment_type)
@command.command() @command.command()
@ -123,7 +123,6 @@ def push_images(ctx):
@click.argument('extra_args', nargs=-1) # help: command: port <service1> <service2> @click.argument('extra_args', nargs=-1) # help: command: port <service1> <service2>
@click.pass_context @click.pass_context
def port(ctx, extra_args): def port(ctx, extra_args):
ctx.obj = make_deploy_context(ctx)
port_operation(ctx, extra_args) port_operation(ctx, extra_args)

View File

@ -24,7 +24,7 @@ from secrets import token_hex
import sys import sys
from stack_orchestrator import constants from stack_orchestrator import constants
from stack_orchestrator.opts import opts from stack_orchestrator.opts import opts
from stack_orchestrator.util import (get_stack_path, get_parsed_deployment_spec, get_parsed_stack_config, from stack_orchestrator.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config,
global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts, global_options, get_yaml, get_pod_list, get_pod_file_path, pod_has_scripts,
get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file, get_pod_script_paths, get_plugin_code_paths, error_exit, env_var_map_from_file,
resolve_config_dir) resolve_config_dir)
@ -238,11 +238,6 @@ def _find_extra_config_dirs(parsed_pod_file, pod):
config_dir = host_path.split("/")[2] config_dir = host_path.split("/")[2]
if config_dir != pod: if config_dir != pod:
config_dirs.add(config_dir) config_dirs.add(config_dir)
for env_file in service_info.get("env_file", []):
if env_file.startswith("../config"):
config_dir = env_file.split("/")[2]
if config_dir != pod:
config_dirs.add(config_dir)
return config_dirs return config_dirs
@ -459,7 +454,7 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
_check_volume_definitions(parsed_spec) _check_volume_definitions(parsed_spec)
stack_name = parsed_spec["stack"] stack_name = parsed_spec["stack"]
deployment_type = parsed_spec[constants.deploy_to_key] deployment_type = parsed_spec[constants.deploy_to_key]
stack_file = get_stack_path(stack_name).joinpath(constants.stack_file_name) stack_file = get_stack_file_path(stack_name)
parsed_stack = get_parsed_stack_config(stack_name) parsed_stack = get_parsed_stack_config(stack_name)
if opts.o.debug: if opts.o.debug:
print(f"parsed spec: {parsed_spec}") print(f"parsed spec: {parsed_spec}")
@ -472,7 +467,7 @@ def create_operation(deployment_command_context, spec_file, deployment_dir, netw
os.mkdir(deployment_dir_path) os.mkdir(deployment_dir_path)
# Copy spec file and the stack file into the deployment dir # Copy spec file and the stack file into the deployment dir
copyfile(spec_file, deployment_dir_path.joinpath(constants.spec_file_name)) copyfile(spec_file, deployment_dir_path.joinpath(constants.spec_file_name))
copyfile(stack_file, deployment_dir_path.joinpath(constants.stack_file_name)) copyfile(stack_file, deployment_dir_path.joinpath(os.path.basename(stack_file)))
_create_deployment_file(deployment_dir_path) _create_deployment_file(deployment_dir_path)
# Copy any config varibles from the spec file into an env file suitable for compose # Copy any config varibles from the spec file into an env file suitable for compose
_write_config_file(spec_file, deployment_dir_path.joinpath(constants.config_file_name)) _write_config_file(spec_file, deployment_dir_path.joinpath(constants.config_file_name))

View File

@ -24,7 +24,7 @@ import uuid
import click import click
from stack_orchestrator.deploy.images import remote_image_exists from stack_orchestrator.deploy.images import remote_image_exists, add_tags_to_image
from stack_orchestrator.deploy.webapp import deploy_webapp from stack_orchestrator.deploy.webapp import deploy_webapp
from stack_orchestrator.deploy.webapp.util import (LaconicRegistryClient, TimedLogger, from stack_orchestrator.deploy.webapp.util import (LaconicRegistryClient, TimedLogger,
build_container_image, push_container_image, build_container_image, push_container_image,
@ -99,62 +99,44 @@ def process_app_deployment_request(
deployment_record = laconic.get_record(app_deployment_crn) deployment_record = laconic.get_record(app_deployment_crn)
deployment_dir = os.path.join(deployment_parent_dir, fqdn) deployment_dir = os.path.join(deployment_parent_dir, fqdn)
# At present we use this to generate a unique but stable ID for the app's host container
# TODO: implement support to derive this transparently from the already-unique deployment id
unique_deployment_id = hashlib.md5(fqdn.encode()).hexdigest()[:16]
deployment_config_file = os.path.join(deployment_dir, "config.env") deployment_config_file = os.path.join(deployment_dir, "config.env")
deployment_container_tag = "laconic-webapp/%s:local" % unique_deployment_id # TODO: Is there any reason not to simplify the hash input to the app_deployment_crn?
deployment_container_tag = "laconic-webapp/%s:local" % hashlib.md5(deployment_dir.encode()).hexdigest()
app_image_shared_tag = f"laconic-webapp/{app.id}:local" app_image_shared_tag = f"laconic-webapp/{app.id}:local"
# b. check for deployment directory (create if necessary) # b. check for deployment directory (create if necessary)
if not os.path.exists(deployment_dir): if not os.path.exists(deployment_dir):
if deployment_record: if deployment_record:
raise Exception("Deployment record %s exists, but not deployment dir %s. Please remove name." % raise Exception("Deployment record %s exists, but not deployment dir %s. Please remove name." %
(app_deployment_crn, deployment_dir)) (app_deployment_crn, deployment_dir))
logger.log(f"Creating webapp deployment in: {deployment_dir} with container id: {deployment_container_tag}") print("deploy_webapp", deployment_dir)
deploy_webapp.create_deployment(ctx, deployment_dir, deployment_container_tag, deploy_webapp.create_deployment(ctx, deployment_dir, deployment_container_tag,
f"https://{fqdn}", kube_config, image_registry, env_filename) f"https://{fqdn}", kube_config, image_registry, env_filename)
elif env_filename: elif env_filename:
shutil.copyfile(env_filename, deployment_config_file) shutil.copyfile(env_filename, deployment_config_file)
needs_k8s_deploy = False needs_k8s_deploy = False
if force_rebuild:
logger.log("--force-rebuild is enabled so the container will always be built now, even if nothing has changed in the app")
# 6. build container (if needed) # 6. build container (if needed)
# TODO: add a comment that explains what this code is doing (not clear to me) if not deployment_record or deployment_record.attributes.application != app.id:
if not deployment_record or deployment_record.attributes.application != app.id or force_rebuild:
needs_k8s_deploy = True needs_k8s_deploy = True
# check if the image already exists # check if the image already exists
shared_tag_exists = remote_image_exists(image_registry, app_image_shared_tag) shared_tag_exists = remote_image_exists(image_registry, app_image_shared_tag)
# Note: in the code below, calls to add_tags_to_image() won't work at present.
# This is because SO deployment code in general re-names the container image
# to be unique to the deployment. This is done transparently
# and so when we call add_tags_to_image() here and try to add tags to the remote image,
# we get the image name wrong. Accordingly I've disabled the relevant code for now.
# This is safe because we are running with --force-rebuild at present
if shared_tag_exists and not force_rebuild: if shared_tag_exists and not force_rebuild:
# simply add our unique tag to the existing image and we are done # simply add our unique tag to the existing image and we are done
logger.log( logger.log(f"Using existing app image {app_image_shared_tag} for {deployment_container_tag}")
f"(SKIPPED) Existing image found for this app: {app_image_shared_tag} " add_tags_to_image(image_registry, app_image_shared_tag, deployment_container_tag)
"tagging it with: {deployment_container_tag} to use in this deployment"
)
# add_tags_to_image(image_registry, app_image_shared_tag, deployment_container_tag)
logger.log("Tag complete") logger.log("Tag complete")
else: else:
extra_build_args = [] # TODO: pull from request extra_build_args = [] # TODO: pull from request
logger.log(f"Building container image: {deployment_container_tag}") logger.log(f"Building container image {deployment_container_tag}")
build_container_image(app, deployment_container_tag, extra_build_args, logger) build_container_image(app, deployment_container_tag, extra_build_args, logger)
logger.log("Build complete") logger.log("Build complete")
logger.log(f"Pushing container image: {deployment_container_tag}") logger.log(f"Pushing container image {deployment_container_tag}")
push_container_image(deployment_dir, logger) push_container_image(deployment_dir, logger)
logger.log("Push complete") logger.log("Push complete")
# The build/push commands above will use the unique deployment tag, so now we need to add the shared tag. # The build/push commands above will use the unique deployment tag, so now we need to add the shared tag.
logger.log( logger.log(f"Updating app image tag {app_image_shared_tag} from build of {deployment_container_tag}")
f"(SKIPPED) Adding global app image tag: {app_image_shared_tag} to newly built image: {deployment_container_tag}" add_tags_to_image(image_registry, deployment_container_tag, app_image_shared_tag)
)
# add_tags_to_image(image_registry, deployment_container_tag, app_image_shared_tag)
logger.log("Tag complete") logger.log("Tag complete")
else:
logger.log("Requested app is already deployed, skipping build and image push")
# 7. update config (if needed) # 7. update config (if needed)
if not deployment_record or file_hash(deployment_config_file) != deployment_record.attributes.meta.config: if not deployment_record or file_hash(deployment_config_file) != deployment_record.attributes.meta.config:

View File

@ -242,7 +242,6 @@ def determine_base_container(clone_dir, app_type="webapp"):
def build_container_image(app_record, tag, extra_build_args=[], logger=None): def build_container_image(app_record, tag, extra_build_args=[], logger=None):
tmpdir = tempfile.mkdtemp() tmpdir = tempfile.mkdtemp()
# TODO: determine if this code could be calling into the Python git library like setup-repositories
try: try:
record_id = app_record["id"] record_id = app_record["id"]
ref = app_record.attributes.repository_ref ref = app_record.attributes.repository_ref
@ -250,16 +249,6 @@ def build_container_image(app_record, tag, extra_build_args=[], logger=None):
clone_dir = os.path.join(tmpdir, record_id) clone_dir = os.path.join(tmpdir, record_id)
logger.log(f"Cloning repository {repo} to {clone_dir} ...") logger.log(f"Cloning repository {repo} to {clone_dir} ...")
# Set github credentials if present running a command like:
# git config --global url."https://${TOKEN}:@github.com/".insteadOf "https://github.com/"
github_token = os.environ.get("DEPLOYER_GITHUB_TOKEN")
if github_token:
logger.log("Github token detected, setting it in the git environment")
git_config_args = [
"git", "config", "--global", f"url.https://{github_token}:@github.com/.insteadOf", "https://github.com/"
]
result = subprocess.run(git_config_args, stdout=logger.file, stderr=logger.file)
result.check_returncode()
if ref: if ref:
# TODO: Determing branch or hash, and use depth 1 if we can. # TODO: Determing branch or hash, and use depth 1 if we can.
git_env = dict(os.environ.copy()) git_env = dict(os.environ.copy())
@ -276,7 +265,6 @@ def build_container_image(app_record, tag, extra_build_args=[], logger=None):
logger.log(f"git checkout failed. Does ref {ref} exist?") logger.log(f"git checkout failed. Does ref {ref} exist?")
raise e raise e
else: else:
# TODO: why is this code different vs the branch above (run vs check_call, and no prompt disable)?
result = subprocess.run(["git", "clone", "--depth", "1", repo, clone_dir], stdout=logger.file, stderr=logger.file) result = subprocess.run(["git", "clone", "--depth", "1", repo, clone_dir], stdout=logger.file, stderr=logger.file)
result.check_returncode() result.check_returncode()
@ -311,12 +299,11 @@ def push_container_image(deployment_dir, logger):
def deploy_to_k8s(deploy_record, deployment_dir, logger): def deploy_to_k8s(deploy_record, deployment_dir, logger):
if not deploy_record: if not deploy_record:
command = "start" command = "up"
else: else:
command = "update" command = "update"
logger.log("Deploying to k8s ...") logger.log("Deploying to k8s ...")
logger.log(f"Running {command} command on deployment dir: {deployment_dir}")
result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, command], result = subprocess.run([sys.argv[0], "deployment", "--dir", deployment_dir, command],
stdout=logger.file, stderr=logger.file) stdout=logger.file, stderr=logger.file)
result.check_returncode() result.check_returncode()

View File

@ -20,12 +20,14 @@ import os
import sys import sys
from decouple import config from decouple import config
import git import git
from git.exc import GitCommandError
from tqdm import tqdm from tqdm import tqdm
import click import click
import importlib.resources import importlib.resources
from pathlib import Path
import yaml
from stack_orchestrator.constants import stack_file_name
from stack_orchestrator.opts import opts from stack_orchestrator.opts import opts
from stack_orchestrator.util import get_parsed_stack_config, include_exclude_check, error_exit, warn_exit from stack_orchestrator.util import include_exclude_check, stack_is_external, error_exit, warn_exit
class GitProgress(git.RemoteProgress): class GitProgress(git.RemoteProgress):
@ -79,13 +81,9 @@ def _get_repo_current_branch_or_tag(full_filesystem_repo_path):
except TypeError: except TypeError:
# This means that the current ref is not a branch, so possibly a tag # This means that the current ref is not a branch, so possibly a tag
# Let's try to get the tag # Let's try to get the tag
try: current_repo_branch_or_tag = git.Repo(full_filesystem_repo_path).git.describe("--tags", "--exact-match")
current_repo_branch_or_tag = git.Repo(full_filesystem_repo_path).git.describe("--tags", "--exact-match") # Note that git is assymetric -- the tag you told it to check out may not be the one
# Note that git is asymmetric -- the tag you told it to check out may not be the one # you get back here (if there are multiple tags associated with the same commit)
# you get back here (if there are multiple tags associated with the same commit)
except GitCommandError:
# If there is no matching branch or tag checked out, just use the current SHA
current_repo_branch_or_tag = git.Repo(full_filesystem_repo_path).commit("HEAD").hexsha
return current_repo_branch_or_tag, is_branch return current_repo_branch_or_tag, is_branch
@ -104,7 +102,7 @@ def process_repo(pull, check_only, git_ssh, dev_root_path, branches_array, fully
full_filesystem_repo_path full_filesystem_repo_path
) if is_present else (None, None) ) if is_present else (None, None)
if not opts.o.quiet: if not opts.o.quiet:
present_text = f"already exists active {'branch' if is_branch else 'ref'}: {current_repo_branch_or_tag}" if is_present \ present_text = f"already exists active {'branch' if is_branch else 'tag'}: {current_repo_branch_or_tag}" if is_present \
else 'Needs to be fetched' else 'Needs to be fetched'
print(f"Checking: {full_filesystem_repo_path}: {present_text}") print(f"Checking: {full_filesystem_repo_path}: {present_text}")
# Quick check that it's actually a repo # Quick check that it's actually a repo
@ -122,7 +120,7 @@ def process_repo(pull, check_only, git_ssh, dev_root_path, branches_array, fully
origin = git_repo.remotes.origin origin = git_repo.remotes.origin
origin.pull(progress=None if opts.o.quiet else GitProgress()) origin.pull(progress=None if opts.o.quiet else GitProgress())
else: else:
print("skipping pull because this repo is not on a branch") print("skipping pull because this repo checked out a tag")
else: else:
print("(git pull skipped)") print("(git pull skipped)")
if not is_present: if not is_present:
@ -224,10 +222,20 @@ def command(ctx, include, exclude, git_ssh, check_only, pull, branches):
repos_in_scope = [] repos_in_scope = []
if stack: if stack:
stack_config = get_parsed_stack_config(stack) if stack_is_external(stack):
if "repos" not in stack_config or stack_config["repos"] is None: stack_file_path = Path(stack).joinpath(stack_file_name)
warn_exit(f"stack {stack} does not define any repositories") else:
repos_in_scope = stack_config["repos"] # In order to be compatible with Python 3.8 we need to use this hack to get the path:
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_file_path = Path(__file__).absolute().parent.parent.joinpath("data", "stacks", stack, stack_file_name)
if not stack_file_path.exists():
error_exit(f"stack {stack} does not exist")
with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r"))
if "repos" not in stack_config or stack_config["repos"] is None:
warn_exit(f"stack {stack} does not define any repositories")
else:
repos_in_scope = stack_config["repos"]
else: else:
repos_in_scope = all_repos repos_in_scope = all_repos

View File

@ -20,7 +20,6 @@ import ruamel.yaml
from pathlib import Path from pathlib import Path
from dotenv import dotenv_values from dotenv import dotenv_values
from typing import Mapping, Set, List from typing import Mapping, Set, List
from stack_orchestrator.constants import stack_file_name, deployment_file_name
def include_exclude_check(s, include, exclude): def include_exclude_check(s, include, exclude):
@ -34,14 +33,11 @@ def include_exclude_check(s, include, exclude):
return s not in exclude_list return s not in exclude_list
def get_stack_path(stack): def get_stack_file_path(stack):
if stack_is_external(stack): # In order to be compatible with Python 3.8 we need to use this hack to get the path:
stack_path = Path(stack) # See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
else: stack_file_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack, "stack.yml")
# In order to be compatible with Python 3.8 we need to use this hack to get the path: return stack_file_path
# See: https://stackoverflow.com/questions/25389095/python-get-path-of-root-project-structure
stack_path = Path(__file__).absolute().parent.joinpath("data", "stacks", stack)
return stack_path
def get_dev_root_path(ctx): def get_dev_root_path(ctx):
@ -56,14 +52,21 @@ def get_dev_root_path(ctx):
# Caller can pass either the name of a stack, or a path to a stack file # Caller can pass either the name of a stack, or a path to a stack file
def get_parsed_stack_config(stack): def get_parsed_stack_config(stack):
stack_file_path = get_stack_path(stack).joinpath(stack_file_name) stack_file_path = stack if isinstance(stack, os.PathLike) else get_stack_file_path(stack)
if stack_file_path.exists(): try:
return get_yaml().load(open(stack_file_path, "r")) with stack_file_path:
# We try here to generate a useful diagnostic error stack_config = get_yaml().load(open(stack_file_path, "r"))
# First check if the stack directory is present return stack_config
if stack_file_path.parent.exists(): except FileNotFoundError as error:
error_exit(f"stack.yml file is missing from stack: {stack}") # We try here to generate a useful diagnostic error
error_exit(f"stack {stack} does not exist") # First check if the stack directory is present
stack_directory = stack_file_path.parent
if os.path.exists(stack_directory):
print(f"Error: stack.yml file is missing from stack: {stack}")
else:
print(f"Error: stack: {stack} does not exist")
print(f"Exiting, error: {error}")
sys.exit(1)
def get_pod_list(parsed_stack): def get_pod_list(parsed_stack):
@ -84,7 +87,7 @@ def get_plugin_code_paths(stack) -> List[Path]:
result: Set[Path] = set() result: Set[Path] = set()
for pod in pods: for pod in pods:
if type(pod) is str: if type(pod) is str:
result.add(get_stack_path(stack)) result.add(get_stack_file_path(stack).parent)
else: else:
pod_root_dir = os.path.join(get_dev_root_path(None), pod["repository"].split("/")[-1], pod["path"]) pod_root_dir = os.path.join(get_dev_root_path(None), pod["repository"].split("/")[-1], pod["path"])
result.add(Path(os.path.join(pod_root_dir, "stack"))) result.add(Path(os.path.join(pod_root_dir, "stack")))
@ -196,13 +199,6 @@ def stack_is_external(stack: str):
return Path(stack).exists() if stack is not None else False return Path(stack).exists() if stack is not None else False
def stack_is_in_deployment(stack: Path):
if isinstance(stack, os.PathLike):
return stack.joinpath(deployment_file_name).exists()
else:
return False
def get_yaml(): def get_yaml():
# See: https://stackoverflow.com/a/45701840/1701505 # See: https://stackoverflow.com/a/45701840/1701505
yaml = ruamel.yaml.YAML() yaml = ruamel.yaml.YAML()

View File

@ -14,7 +14,7 @@
# along with this program. If not, see <http:#www.gnu.org/licenses/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
import click import click
from importlib import resources, metadata import importlib.resources
@click.command() @click.command()
@ -24,11 +24,8 @@ def command(ctx):
# See: https://stackoverflow.com/a/20885799/1701505 # See: https://stackoverflow.com/a/20885799/1701505
from stack_orchestrator import data from stack_orchestrator import data
if resources.is_resource(data, "build_tag.txt"): with importlib.resources.open_text(data, "build_tag.txt") as version_file:
with resources.open_text(data, "build_tag.txt") as version_file: # TODO: code better version that skips comment lines
# TODO: code better version that skips comment lines version_string = version_file.read().splitlines()[1]
version_string = version_file.read().splitlines()[1]
else:
version_string = metadata.version("laconic-stack-orchestrator") + "-unknown"
print(version_string) print(f"Version: {version_string}")

View File

@ -18,20 +18,6 @@ do
rm -rf ${node_network_dir} rm -rf ${node_network_dir}
fi fi
done done
echo "Deleting any existing deployments..."
for (( i=1 ; i<=$node_count ; i++ ));
do
node_deployment_dir=${node_dir_prefix}${i}-deployment
node_spec_file=${node_dir_prefix}${i}-spec.yml
if [[ -d $node_deployment_dir ]]; then
echo "Deleting ${node_deployment_dir}"
rm -rf ${node_deployment_dir}
fi
if [[ -f $node_spec_file ]]; then
echo "Deleting ${node_spec_file}"
rm ${node_spec_file}
fi
done
echo "Initalizing ${node_count} nodes networks..." echo "Initalizing ${node_count} nodes networks..."
for (( i=1 ; i<=$node_count ; i++ )); for (( i=1 ; i<=$node_count ; i++ ));
@ -70,12 +56,3 @@ do
node_network_dir=${node_dir_prefix}${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} laconic-so --stack mainnet-laconic deploy setup --network-dir ${node_network_dir} --create-network --genesis-file ${genesis_file}
done done
# Create deployments
echo "Creating ${node_count} deployments..."
for (( i=1 ; i<=$node_count ; i++ ));
do
node_network_dir=${node_dir_prefix}${i}
laconic-so --stack mainnet-laconic deploy init --output ${node_network_dir}-spec.yml
laconic-so --stack mainnet-laconic deploy create --deployment-dir ${node_network_dir}-deployment --spec-file ${node_dir_prefix}${i}-spec.yml --network-dir ${node_network_dir}
done

View File

@ -10,11 +10,8 @@ echo "Environment variables:"
env env
# Test basic stack-orchestrator webapp # Test basic stack-orchestrator webapp
echo "Running stack-orchestrator webapp test" echo "Running stack-orchestrator webapp test"
if [ "$1" == "from-path" ]; then # Bit of a hack, test the most recent package
TEST_TARGET_SO="laconic-so" TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
else
TEST_TARGET_SO=$( ls -t1 ./package/laconic-so* | head -1 )
fi
# Set a non-default repo dir # Set a non-default repo dir
export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir
echo "Testing this package: $TEST_TARGET_SO" echo "Testing this package: $TEST_TARGET_SO"
@ -33,17 +30,14 @@ CHECK="SPECIAL_01234567890_TEST_STRING"
set +e set +e
app_image_name="cerc/test-progressive-web-app:local" CONTAINER_ID=$(docker run -p 3000:80 -d -e CERC_SCRIPT_DEBUG=$CERC_SCRIPT_DEBUG cerc/test-progressive-web-app:local)
CONTAINER_ID=$(docker run -p 3000:80 -d -e CERC_SCRIPT_DEBUG=$CERC_SCRIPT_DEBUG ${app_image_name})
sleep 3 sleep 3
wget --tries 20 --retry-connrefused --waitretry=3 -O test.before -m http://localhost:3000 wget --tries 20 --retry-connrefused --waitretry=3 -O test.before -m http://localhost:3000
docker logs $CONTAINER_ID docker logs $CONTAINER_ID
docker remove -f $CONTAINER_ID docker remove -f $CONTAINER_ID
echo "Running app container test" CONTAINER_ID=$(docker run -p 3000:80 -e CERC_WEBAPP_DEBUG=$CHECK -e CERC_SCRIPT_DEBUG=$CERC_SCRIPT_DEBUG -d cerc/test-progressive-web-app:local)
CONTAINER_ID=$(docker run -p 3000:80 -e CERC_WEBAPP_DEBUG=$CHECK -e CERC_SCRIPT_DEBUG=$CERC_SCRIPT_DEBUG -d ${app_image_name})
sleep 3 sleep 3
wget --tries 20 --retry-connrefused --waitretry=3 -O test.after -m http://localhost:3000 wget --tries 20 --retry-connrefused --waitretry=3 -O test.after -m http://localhost:3000
@ -69,18 +63,4 @@ else
echo "AFTER: PASSED" echo "AFTER: PASSED"
fi fi
echo "Running deployment create test"
# Note: this is not a full test -- all we're testing here is that the deploy-webapp create command doesn't crash
test_deployment_dir=$CERC_REPO_BASE_DIR/test-deployment-dir
fake_k8s_config_file=$CERC_REPO_BASE_DIR/kube-config.yml
touch ${fake_k8s_config_file}
$TEST_TARGET_SO deploy-webapp create --kube-config ${fake_k8s_config_file} --deployment-dir ${test_deployment_dir} --image ${app_image_name} --url https://my-test-app.example.com
if [ -d ${test_deployment_dir} ]; then
echo "PASSED"
else
echo "FAILED"
exit 1
fi
exit 0 exit 0