Compare commits

..
Author SHA1 Message Date
iskay bd8c78e1a3 update fixturenet-plugeth test 2023-11-02 09:26:47 -04:00
telackey fd5779f967 Fix KeyError accessing config. (#620) 2023-10-31 12:29:19 -05:00
Ian d854dd5c81 Update fixturenet-laconicd.yml 2023-10-30 15:44:46 -04:00
Ian 948f9f4287 Merge pull request #611 from cerc-io/iskay/fixturenet-laconicd-test
add fixturenet-laconicd test
2023-10-30 11:50:33 -04:00
dboreham b92d9cd7dd Update stack README.md to use config directive 2023-10-29 23:16:39 -06:00
dboreham 86076c7ed8 Fix deployer.exec() (#619) 2023-10-29 22:26:15 -06:00
telackey 8cac598679 Split act-runner into its own pod and offer as a distinct stack. (#612)
* Split act-runner into its own pod and offer as a distinct stack.
2023-10-27 13:57:13 -05:00
dboreham 6130eab5cb k8s deploy (#614) 2023-10-27 10:19:44 -06:00
18 changed files with 390 additions and 70 deletions
@@ -12,12 +12,6 @@ jobs:
name: "Run fixturenet-laconicd test suite" name: "Run fixturenet-laconicd test suite"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Setup jq'
run: apt-get install jq -y
- name: 'Check jq'
run: |
which jq
jq --version
- name: "Clone project repository" - name: "Clone project repository"
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: "Install Python" - name: "Install Python"
+30
View File
@@ -0,0 +1,30 @@
name: Fixturenet-Plugeth Test
on:
push:
branches: '*'
paths:
- '!**'
- '.github/workflows/triggers/fixturenet-plugeth-test'
jobs:
test:
name: "Run fixturenet-plugeth test suite"
runs-on: ubuntu-latest
steps:
- name: "Clone project repository"
uses: actions/checkout@v3
- name: "Install Python"
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-plugeth tests"
run: ./tests/fixturenet-plugeth/run-test.sh
@@ -0,0 +1,3 @@
Change this file to trigger running the fixturenet-plugeth-test CI job
trigger
@@ -2,4 +2,4 @@
# Build a local version of the task executor for act-runner # Build a local version of the task executor for act-runner
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 ) SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
docker build -t cerc/act-runner-task-executor:local -f ${CERC_REPO_BASE_DIR}/hosting/gitea/Dockerfile.task-executor ${build_command_args} ${SCRIPT_DIR} docker build -t cerc/act-runner-task-executor:local -f ${CERC_REPO_BASE_DIR}/hosting/act-runner/Dockerfile.task-executor ${build_command_args} ${SCRIPT_DIR}
+13
View File
@@ -0,0 +1,13 @@
# act-runner stack
## Example
```
$ laconic-so --stack act-runner deploy init --output act-runner-1.yml --config CERC_GITEA_RUNNER_REGISTRATION_TOKEN=FOO
$ laconic-so --stack act-runner deploy create --spec-file act-runner-1.yml --deployment-dir ~/opt/deployments/act-runner-1
$ laconic-so deployment --dir ~/opt/deployments/act-runner-1 up
$ laconic-so --stack act-runner deploy init --output act-runner-2.yml --config CERC_GITEA_RUNNER_REGISTRATION_TOKEN=BAR
$ laconic-so --stack act-runner deploy create --spec-file act-runner-2.yml --deployment-dir ~/opt/deployments/act-runner-2
$ laconic-so deployment --dir ~/opt/deployments/act-runner-2 up
```
+15
View File
@@ -0,0 +1,15 @@
version: "1.1"
name: act-runner
description: "Local act-runner"
repos:
- git.vdb.to/cerc-io/hosting
- gitea.com/gitea/act_runner
containers:
- cerc/act-runner
- cerc/act-runner-task-executor
pods:
- name: act-runner
repository: cerc-io/hosting
path: act-runner
pre_start_command: "pre_start.sh"
post_start_command: "post_start.sh"
@@ -13,3 +13,8 @@ pods:
path: gitea path: gitea
pre_start_command: "run-this-first.sh" pre_start_command: "run-this-first.sh"
post_start_command: "initialize-gitea.sh" post_start_command: "initialize-gitea.sh"
- name: act-runner
repository: cerc-io/hosting
path: act-runner
pre_start_command: "pre_start.sh"
post_start_command: "post_start.sh"
+2 -2
View File
@@ -48,9 +48,9 @@ class DockerDeployer(Deployer):
except DockerException as e: except DockerException as e:
raise DeployerException(e) raise DeployerException(e)
def execute(self, service, command, envs): def execute(self, service, command, tty, envs):
try: try:
return self.docker.compose.execute(service=service, command=command, envs=envs) return self.docker.compose.execute(service=service, command=command, tty=tty, envs=envs)
except DockerException as e: except DockerException as e:
raise DeployerException(e) raise DeployerException(e)
+3 -3
View File
@@ -151,7 +151,7 @@ def exec_operation(ctx, extra_args):
if global_context.verbose: if global_context.verbose:
print(f"Running compose exec {service_name} {command_to_exec}") print(f"Running compose exec {service_name} {command_to_exec}")
try: try:
ctx.obj.deployer.execute(service_name, command_to_exec, envs=container_exec_env) ctx.obj.deployer.execute(service_name, command_to_exec, tty=True, envs=container_exec_env)
except DeployerException: except DeployerException:
print("container command returned error exit status") print("container command returned error exit status")
@@ -307,7 +307,7 @@ def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_path}.yml") compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_path}.yml")
else: else:
if deployment: if deployment:
compose_file_name = os.path.join(compose_dir, "docker-compose.yml") compose_file_name = os.path.join(compose_dir, f"docker-compose-{pod_name}.yml")
pod_pre_start_command = pod["pre_start_command"] pod_pre_start_command = pod["pre_start_command"]
pod_post_start_command = pod["post_start_command"] pod_post_start_command = pod["post_start_command"]
script_dir = compose_dir.parent.joinpath("pods", pod_name, "scripts") script_dir = compose_dir.parent.joinpath("pods", pod_name, "scripts")
@@ -317,7 +317,7 @@ def _make_cluster_context(ctx, stack, include, exclude, cluster, env_file):
post_start_commands.append(os.path.join(script_dir, pod_post_start_command)) post_start_commands.append(os.path.join(script_dir, pod_post_start_command))
else: else:
pod_root_dir = os.path.join(dev_root_path, pod_repository.split("/")[-1], pod["path"]) pod_root_dir = os.path.join(dev_root_path, pod_repository.split("/")[-1], pod["path"])
compose_file_name = os.path.join(pod_root_dir, "docker-compose.yml") compose_file_name = os.path.join(pod_root_dir, f"docker-compose-{pod_name}.yml")
pod_pre_start_command = pod["pre_start_command"] pod_pre_start_command = pod["pre_start_command"]
pod_post_start_command = pod["post_start_command"] pod_post_start_command = pod["post_start_command"]
if pod_pre_start_command is not None: if pod_pre_start_command is not None:
+1 -1
View File
@@ -35,7 +35,7 @@ class Deployer(ABC):
pass pass
@abstractmethod @abstractmethod
def execute(self, service_name, command, envs): def execute(self, service_name, command, tty, envs):
pass pass
@abstractmethod @abstractmethod
+40 -34
View File
@@ -22,7 +22,7 @@ import random
from shutil import copy, copyfile, copytree from shutil import copy, copyfile, copytree
import sys import sys
from app.util import (get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml, from app.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, get_pod_script_paths, get_plugin_code_path) get_pod_list, get_pod_file_path, pod_has_scripts, get_pod_script_paths, get_plugin_code_paths)
from app.deploy.deploy_types import DeploymentContext, DeployCommandContext, LaconicStackSetupCommand from app.deploy.deploy_types import DeploymentContext, DeployCommandContext, LaconicStackSetupCommand
@@ -106,9 +106,10 @@ def _fixup_pod_file(pod, spec, compose_dir):
pod["services"][container_name]["ports"] = container_ports pod["services"][container_name]["ports"] = container_ports
def _commands_plugin_path(ctx: DeployCommandContext): def _commands_plugin_paths(ctx: DeployCommandContext):
plugin_path = get_plugin_code_path(ctx.stack) plugin_paths = get_plugin_code_paths(ctx.stack)
return plugin_path.joinpath("deploy", "commands.py") ret = [p.joinpath("deploy", "commands.py") for p in plugin_paths]
return ret
# See: https://stackoverflow.com/a/54625079/1701505 # See: https://stackoverflow.com/a/54625079/1701505
@@ -120,15 +121,23 @@ def call_stack_deploy_init(deploy_command_context):
# Link with the python file in the stack # Link with the python file in the stack
# Call a function in it # Call a function in it
# If no function found, return None # If no function found, return None
python_file_path = _commands_plugin_path(deploy_command_context) python_file_paths = _commands_plugin_paths(deploy_command_context)
if python_file_path.exists():
spec = util.spec_from_file_location("commands", python_file_path) ret = None
imported_stack = util.module_from_spec(spec) init_done = False
spec.loader.exec_module(imported_stack) for python_file_path in python_file_paths:
if _has_method(imported_stack, "init"): if python_file_path.exists():
return imported_stack.init(deploy_command_context) spec = util.spec_from_file_location("commands", python_file_path)
else: imported_stack = util.module_from_spec(spec)
return None spec.loader.exec_module(imported_stack)
if _has_method(imported_stack, "init"):
if not init_done:
ret = imported_stack.init(deploy_command_context)
init_done = True
else:
# TODO: remove this restriction
print(f"Skipping init() from plugin {python_file_path}. Only one init() is allowed.")
return ret
# TODO: fold this with function above # TODO: fold this with function above
@@ -136,16 +145,14 @@ def call_stack_deploy_setup(deploy_command_context, parameters: LaconicStackSetu
# Link with the python file in the stack # Link with the python file in the stack
# Call a function in it # Call a function in it
# If no function found, return None # If no function found, return None
python_file_path = _commands_plugin_path(deploy_command_context) python_file_paths = _commands_plugin_paths(deploy_command_context)
print(f"Path: {python_file_path}") for python_file_path in python_file_paths:
if python_file_path.exists(): if python_file_path.exists():
spec = util.spec_from_file_location("commands", python_file_path) spec = util.spec_from_file_location("commands", python_file_path)
imported_stack = util.module_from_spec(spec) imported_stack = util.module_from_spec(spec)
spec.loader.exec_module(imported_stack) spec.loader.exec_module(imported_stack)
if _has_method(imported_stack, "setup"): if _has_method(imported_stack, "setup"):
return imported_stack.setup(deploy_command_context, parameters, extra_args) imported_stack.setup(deploy_command_context, parameters, extra_args)
else:
return None
# TODO: fold this with function above # TODO: fold this with function above
@@ -153,15 +160,14 @@ def call_stack_deploy_create(deployment_context, extra_args):
# Link with the python file in the stack # Link with the python file in the stack
# Call a function in it # Call a function in it
# If no function found, return None # If no function found, return None
python_file_path = _commands_plugin_path(deployment_context.command_context) python_file_paths = _commands_plugin_paths(deployment_context.command_context)
if python_file_path.exists(): for python_file_path in python_file_paths:
spec = util.spec_from_file_location("commands", python_file_path) if python_file_path.exists():
imported_stack = util.module_from_spec(spec) spec = util.spec_from_file_location("commands", python_file_path)
spec.loader.exec_module(imported_stack) imported_stack = util.module_from_spec(spec)
if _has_method(imported_stack, "create"): spec.loader.exec_module(imported_stack)
return imported_stack.create(deployment_context, extra_args) if _has_method(imported_stack, "create"):
else: imported_stack.create(deployment_context, extra_args)
return None
# Inspect the pod yaml to find config files referenced in subdirectories # Inspect the pod yaml to find config files referenced in subdirectories
@@ -255,7 +261,7 @@ def init(ctx, config, output, map_ports_to_host):
config_variables = _parse_config_variables(config) config_variables = _parse_config_variables(config)
if config_variables: if config_variables:
# Implement merge, since update() overwrites # Implement merge, since update() overwrites
orig_config = spec_file_content["config"] orig_config = spec_file_content.get("config", {})
new_config = config_variables["config"] new_config = config_variables["config"]
merged_config = {**new_config, **orig_config} merged_config = {**new_config, **orig_config}
spec_file_content.update({"config": merged_config}) spec_file_content.update({"config": merged_config})
@@ -336,7 +342,7 @@ def create(ctx, spec_file, deployment_dir, network_dir, initial_peers):
if global_options(ctx).debug: if global_options(ctx).debug:
print(f"extra config dirs: {extra_config_dirs}") print(f"extra config dirs: {extra_config_dirs}")
_fixup_pod_file(parsed_pod_file, parsed_spec, destination_compose_dir) _fixup_pod_file(parsed_pod_file, parsed_spec, destination_compose_dir)
with open(os.path.join(destination_compose_dir, os.path.basename(pod_file_path)), "w") as output_file: with open(os.path.join(destination_compose_dir, "docker-compose-%s.yml" % pod), "w") as output_file:
yaml.dump(parsed_pod_file, output_file) yaml.dump(parsed_pod_file, output_file)
# Copy the config files for the pod, if any # Copy the config files for the pod, if any
config_dirs = {pod} config_dirs = {pod}
+84
View File
@@ -0,0 +1,84 @@
# Copyright © 2023 Vulcanize
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from kubernetes import client
from typing import Any, List, Set
from app.opts import opts
from app.util import get_yaml
class ClusterInfo:
parsed_pod_yaml_map: Any = {}
image_set: Set[str] = set()
app_name: str = "test-app"
deployment_name: str = "test-deployment"
def __init__(self) -> None:
pass
def int_from_pod_files(self, pod_files: List[str]):
for pod_file in pod_files:
with open(pod_file, "r") as pod_file_descriptor:
parsed_pod_file = get_yaml().load(pod_file_descriptor)
self.parsed_pod_yaml_map[pod_file] = parsed_pod_file
if opts.o.debug:
print(f"parsed_pod_yaml_map: {self.parsed_pod_yaml_map}")
# Find the set of images in the pods
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]
image = service_info["image"]
self.image_set.add(image)
if opts.o.debug:
print(f"image_set: {self.image_set}")
def get_deployment(self):
containers = []
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:
container_name = service_name
service_info = services[service_name]
image = service_info["image"]
container = client.V1Container(
name=container_name,
image=image,
ports=[client.V1ContainerPort(container_port=80)],
resources=client.V1ResourceRequirements(
requests={"cpu": "100m", "memory": "200Mi"},
limits={"cpu": "500m", "memory": "500Mi"},
),
)
containers.append(container)
template = client.V1PodTemplateSpec(
metadata=client.V1ObjectMeta(labels={"app": self.app_name}),
spec=client.V1PodSpec(containers=containers),
)
spec = client.V1DeploymentSpec(
replicas=1, template=template, selector={
"matchLabels":
{"app": self.app_name}})
deployment = client.V1Deployment(
api_version="apps/v1",
kind="Deployment",
metadata=client.V1ObjectMeta(name=self.deployment_name),
spec=spec,
)
return deployment
+60 -7
View File
@@ -14,33 +14,86 @@
# along with this program. If not, see <http:#www.gnu.org/licenses/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
from kubernetes import client, config from kubernetes import client, config
from app.deploy.deployer import Deployer from app.deploy.deployer import Deployer
from app.deploy.k8s.helpers import create_cluster, destroy_cluster, load_images_into_kind
from app.deploy.k8s.helpers import pods_in_deployment, log_stream_from_string
from app.deploy.k8s.cluster_info import ClusterInfo
from app.opts import opts
class K8sDeployer(Deployer): class K8sDeployer(Deployer):
name: str = "k8s" name: str = "k8s"
core_api: client.CoreV1Api
apps_api: client.AppsV1Api
kind_cluster_name: str
cluster_info : ClusterInfo
def __init__(self, compose_files, compose_project_name, compose_env_file) -> None: def __init__(self, compose_files, compose_project_name, compose_env_file) -> None:
config.load_kube_config() if (opts.o.debug):
self.client = client.CoreV1Api() print(f"Compose files: {compose_files}")
print(f"Project name: {compose_project_name}")
print(f"Env file: {compose_env_file}")
self.kind_cluster_name = compose_project_name
self.cluster_info = ClusterInfo()
self.cluster_info.int_from_pod_files(compose_files)
def connect_api(self):
config.load_kube_config(context=f"kind-{self.kind_cluster_name}")
self.core_api = client.CoreV1Api()
self.apps_api = client.AppsV1Api()
def up(self, detach, services): def up(self, detach, services):
pass # Create the kind cluster
create_cluster(self.kind_cluster_name)
self.connect_api()
# Ensure the referenced containers are copied into kind
load_images_into_kind(self.kind_cluster_name, self.cluster_info.image_set)
# Process compose files into a Deployment
deployment = self.cluster_info.get_deployment()
# Create the k8s objects
resp = self.apps_api.create_namespaced_deployment(
body=deployment, namespace="default"
)
if opts.o.debug:
print("Deployment created.\n")
print(f"{resp.metadata.namespace} {resp.metadata.name} \
{resp.metadata.generation} {resp.spec.template.spec.containers[0].image}")
def down(self, timeout, volumes): def down(self, timeout, volumes):
pass # Delete the k8s objects
# Destroy the kind cluster
destroy_cluster(self.kind_cluster_name)
def ps(self): def ps(self):
pass self.connect_api()
# Call whatever API we need to get the running container list
ret = self.core_api.list_pod_for_all_namespaces(watch=False)
if ret.items:
for i in ret.items:
print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))
ret = self.core_api.list_node(pretty=True, watch=False)
return []
def port(self, service, private_port): def port(self, service, private_port):
# Since we handle the port mapping, need to figure out where this comes from
# Also look into whether it makes sense to get ports for k8s
pass pass
def execute(self, service_name, command, envs): def execute(self, service_name, command, tty, envs):
# Call the API to execute a command in a running container
pass pass
def logs(self, services, tail, follow, stream): def logs(self, services, tail, follow, stream):
pass self.connect_api()
pods = pods_in_deployment(self.core_api, "test-deployment")
if len(pods) > 1:
print("Warning: more than one pod in the deployment")
k8s_pod_name = pods[0]
log_data = self.core_api.read_namespaced_pod_log(k8s_pod_name, namespace="default", container="test")
return log_stream_from_string(log_data)
def run(self, image, command, user, volumes, entrypoint=None): def run(self, image, command, user, volumes, entrypoint=None):
# We need to figure out how to do this -- check why we're being called first
pass pass
+57
View File
@@ -0,0 +1,57 @@
# Copyright © 2023 Vulcanize
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from kubernetes import client
import subprocess
from typing import Set
from app.opts import opts
def _run_command(command: str):
if opts.o.debug:
print(f"Running: {command}")
result = subprocess.run(command, shell=True)
if opts.o.debug:
print(f"Result: {result}")
def create_cluster(name: str):
_run_command(f"kind create cluster --name {name}")
def destroy_cluster(name: str):
_run_command(f"kind delete cluster --name {name}")
def load_images_into_kind(kind_cluster_name: str, image_set: Set[str]):
for image in image_set:
_run_command(f"kind load docker-image {image} --name {kind_cluster_name}")
def pods_in_deployment(core_api: client.CoreV1Api, deployment_name: str):
pods = []
pod_response = core_api.list_namespaced_pod(namespace="default", label_selector="app=test-app")
if opts.o.debug:
print(f"pod_response: {pod_response}")
for pod_info in pod_response.items:
pod_name = pod_info.metadata.name
pods.append(pod_name)
return pods
def log_stream_from_string(s: str):
# Note response has to be UTF-8 encoded because the caller expects to decode it
yield ("ignore", s.encode())
+20
View File
@@ -0,0 +1,20 @@
# Copyright © 2023 Vulcanize
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# 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/>.
from app.command_types import CommandOptions
class opts:
o: CommandOptions = None
+8 -8
View File
@@ -79,16 +79,16 @@ def get_pod_list(parsed_stack):
return result return result
def get_plugin_code_path(stack): def get_plugin_code_paths(stack):
parsed_stack = get_parsed_stack_config(stack) parsed_stack = get_parsed_stack_config(stack)
pods = parsed_stack["pods"] pods = parsed_stack["pods"]
# TODO: Hack result = []
pod = pods[0] for pod in pods:
if type(pod) is str: if type(pod) is str:
result = get_stack_file_path(stack).parent result.append(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 = Path(os.path.join(pod_root_dir, "stack")) result.append(Path(os.path.join(pod_root_dir, "stack")))
return result return result
+4 -1
View File
@@ -22,6 +22,7 @@ from app.build import build_npms
from app.deploy import deploy from app.deploy import deploy
from app import version from app import version
from app.deploy import deployment from app.deploy import deployment
from app import opts
from app import update from app import update
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@@ -39,7 +40,9 @@ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.pass_context @click.pass_context
def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error): def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error):
"""Laconic Stack Orchestrator""" """Laconic Stack Orchestrator"""
ctx.obj = CommandOptions(stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error) command_options = CommandOptions(stack, quiet, verbose, dry_run, local_stack, debug, continue_on_error)
opts.opts.o = command_options
ctx.obj = command_options
cli.add_command(setup_repositories.command, "setup-repositories") cli.add_command(setup_repositories.command, "setup-repositories")
+44 -7
View File
@@ -24,21 +24,58 @@ echo "Deploying the cluster"
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy up $TEST_TARGET_SO --stack $CERC_STACK_NAME deploy up
# Verify that the fixturenet is up and running # 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 ps
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy exec fixturenet-eth-bootnode-lighthouse /scripts/status-internal.sh # $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 timeout=900 # 15 minutes
sleep 12 echo "$(date +"%Y-%m-%d %T"): Getting initial block number. Timeout set to $timeout seconds"
subsequent_block_number=$($TEST_TARGET_SO --stack $CERC_STACK_NAME deploy exec foundry "cast block-number") 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 $CERC_STACK_NAME 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 $CERC_STACK_NAME 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)) 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 # Block height difference should be between 1 and some small number
if [[ $block_number_difference -gt 1 && $block_number_difference -lt 10 ]]; then if [[ $block_number_difference -gt 1 && $block_number_difference -lt 100 ]]; then
echo "Test passed" echo "Test passed"
test_result=0 test_result=0
else else
echo "Test failed: block numbers were ${initial_block_number} and ${subsequent_block_number}" echo "Test failed: block numbers were ${initial_block_number} and ${subsequent_block_number}"
echo "Logs from stack:"
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy logs
test_result=1 test_result=1
fi fi
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy down
$TEST_TARGET_SO --stack $CERC_STACK_NAME deploy down --delete-volumes
echo "Removing cloned repositories" echo "Removing cloned repositories"
rm -rf $CERC_REPO_BASE_DIR rm -rf $CERC_REPO_BASE_DIR
exit $test_result exit $test_result