diff --git a/app/base.py b/app/base.py
index f6cf0650..47ed56c6 100644
--- a/app/base.py
+++ b/app/base.py
@@ -15,7 +15,7 @@
import os
from abc import ABC, abstractmethod
-from .deploy_system import get_stack_status
+from .deploy import get_stack_status
def get_stack(config, stack):
diff --git a/app/data/stacks/mainnet-laconic/README.md b/app/data/stacks/mainnet-laconic/README.md
new file mode 100644
index 00000000..67984e5b
--- /dev/null
+++ b/app/data/stacks/mainnet-laconic/README.md
@@ -0,0 +1,2 @@
+# Laconic Mainnet Deployment (experimental)
+
diff --git a/app/data/stacks/mainnet-laconic/deploy/commands.py b/app/data/stacks/mainnet-laconic/deploy/commands.py
new file mode 100644
index 00000000..292b0f07
--- /dev/null
+++ b/app/data/stacks/mainnet-laconic/deploy/commands.py
@@ -0,0 +1,50 @@
+# Copyright © 2022, 2023 Cerc
+
+# 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 .
+
+import click
+import os
+from shutil import copyfile
+import sys
+
+default_spec_file_content = """data_dir: /my/path
+node_name: my-node-name
+"""
+
+
+def make_default_deployment_dir():
+ return "deployment-001"
+
+@click.command()
+@click.option("--output", required=True, help="Write yaml spec file here")
+@click.pass_context
+def init(ctx, output):
+ with open(output, "w") as output_file:
+ output_file.write(default_spec_file_content)
+
+
+@click.command()
+@click.option("--spec-file", required=True, help="Spec file to use to create this deployment")
+@click.option("--deployment-dir", help="Create deployment files in this directory")
+@click.pass_context
+def create(ctx, spec_file, deployment_dir):
+ # TODO: check spec-file exists and is readable
+ if deployment_dir is None:
+ deployment_dir = make_default_deployment_dir()
+ if os.path.exists(deployment_dir):
+ print(f"Error: {deployment_dir} already exists")
+ sys.exit(1)
+ os.mkdir(deployment_dir)
+ # Copy spec file into the deployment dir
+ copyfile(spec_file, os.path.join(deployment_dir, os.path.basename(spec_file)))
diff --git a/app/data/stacks/mainnet-laconic/stack.yml b/app/data/stacks/mainnet-laconic/stack.yml
new file mode 100644
index 00000000..1422d6ba
--- /dev/null
+++ b/app/data/stacks/mainnet-laconic/stack.yml
@@ -0,0 +1,32 @@
+version: "1.0"
+name: mainnet-laconic
+description: "Mainnet laconic node"
+repos:
+ - cerc-io/laconicd
+ - lirewine/debug
+ - lirewine/crypto
+ - lirewine/gem
+ - lirewine/sdk
+ - cerc-io/laconic-sdk
+ - cerc-io/laconic-registry-cli
+ - cerc-io/laconic-console
+npms:
+ - laconic-sdk
+ - laconic-registry-cli
+ - debug
+ - crypto
+ - sdk
+ - gem
+ - laconic-console
+containers:
+ - cerc/laconicd
+ - cerc/laconic-registry-cli
+ - cerc/laconic-console-host
+pods:
+ - mainnet-laconicd
+ - laconic-console
+config:
+ cli:
+ key: laconicd.mykey
+ address: laconicd.myaddress
+
diff --git a/app/data/stacks/mainnet-laconic/test/run-mainnet-laconic-test.sh b/app/data/stacks/mainnet-laconic/test/run-mainnet-laconic-test.sh
new file mode 100755
index 00000000..3e25f5dc
--- /dev/null
+++ b/app/data/stacks/mainnet-laconic/test/run-mainnet-laconic-test.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+set -e
+if [ -n "$CERC_SCRIPT_DEBUG" ]; then
+ set -x
+fi
+# Dump environment variables for debugging
+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 )
+# Set a non-default repo dir
+export CERC_REPO_BASE_DIR=~/stack-orchestrator-test/repo-base-dir
+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"
+rm -rf $CERC_REPO_BASE_DIR
+mkdir -p $CERC_REPO_BASE_DIR
+# Test bringing the test container up and down
+# with and without volume removal
+$TEST_TARGET_SO --stack test setup-repositories
+$TEST_TARGET_SO --stack test build-containers
+$TEST_TARGET_SO --stack test deploy up
+$TEST_TARGET_SO --stack test deploy down
+# The next time we bring the container up the volume will be old (from the previous run above)
+$TEST_TARGET_SO --stack test deploy up
+log_output_1=$( $TEST_TARGET_SO --stack test deploy logs )
+if [[ "$log_output_1" == *"Filesystem is old"* ]]; then
+ echo "Retain volumes test: passed"
+else
+ echo "Retain volumes test: FAILED"
+ exit 1
+fi
+$TEST_TARGET_SO --stack test deploy down --delete-volumes
+# Now when we bring the container up the volume will be new again
+$TEST_TARGET_SO --stack test deploy up
+log_output_2=$( $TEST_TARGET_SO --stack test deploy logs )
+if [[ "$log_output_2" == *"Filesystem is fresh"* ]]; then
+ echo "Delete volumes test: passed"
+else
+ echo "Delete volumes test: FAILED"
+ exit 1
+fi
+$TEST_TARGET_SO --stack test deploy down --delete-volumes
+echo "Test passed"
diff --git a/app/deploy_system.py b/app/deploy.py
similarity index 97%
rename from app/deploy_system.py
rename to app/deploy.py
index 2782ce5d..80f2ff27 100644
--- a/app/deploy_system.py
+++ b/app/deploy.py
@@ -24,10 +24,11 @@ from decouple import config
import subprocess
from python_on_whales import DockerClient, DockerException
import click
-import importlib.resources
+from importlib import resources, util
from pathlib import Path
from .util import include_exclude_check, get_parsed_stack_config
+
class DeployCommandContext(object):
def __init__(self, cluster_context, docker):
self.cluster_context = cluster_context
@@ -225,7 +226,7 @@ def _make_cluster_context(ctx, include, exclude, cluster, env_file):
# See: https://stackoverflow.com/a/20885799/1701505
from . import data
- with importlib.resources.open_text(data, "pod-list.txt") as pod_list_file:
+ with resources.open_text(data, "pod-list.txt") as pod_list_file:
all_pods = pod_list_file.read().splitlines()
pods_in_scope = []
@@ -376,3 +377,13 @@ def _orchestrate_cluster_config(ctx, cluster_config, docker, container_exec_env)
waiting_for_data = False
if ctx.debug:
print(f"destination output: {destination_output}")
+
+
+# TODO: figure out how to do this dynamically
+stack = "mainnet-laconic"
+module_name = "commands"
+spec = util.spec_from_file_location(module_name, "./app/data/stacks/" + stack + "/deploy/commands.py")
+imported_stack = util.module_from_spec(spec)
+spec.loader.exec_module(imported_stack)
+command.add_command(imported_stack.init)
+command.add_command(imported_stack.create)
diff --git a/app/deployments.py b/app/deployments.py
new file mode 100644
index 00000000..7bab5cec
--- /dev/null
+++ b/app/deployments.py
@@ -0,0 +1,21 @@
+# Copyright © 2022, 2023 Cerc
+
+# 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 .
+
+import click
+
+
+@click.command()
+def init():
+ pass
diff --git a/cli.py b/cli.py
index b0d2f34c..b7d19786 100644
--- a/cli.py
+++ b/cli.py
@@ -19,7 +19,7 @@ from dataclasses import dataclass
from app import setup_repositories
from app import build_containers
from app import build_npms
-from app import deploy_system
+from app import deploy
from app import version
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@@ -54,6 +54,6 @@ def cli(ctx, stack, quiet, verbose, dry_run, local_stack, debug, continue_on_err
cli.add_command(setup_repositories.command, "setup-repositories")
cli.add_command(build_containers.command, "build-containers")
cli.add_command(build_npms.command, "build-npms")
-cli.add_command(deploy_system.command, "deploy") # deploy is an alias for deploy-system
-cli.add_command(deploy_system.command, "deploy-system")
+cli.add_command(deploy.command, "deploy") # deploy is an alias for deploy-system
+cli.add_command(deploy.command, "deploy-system")
cli.add_command(version.command, "version")