This commit is contained in:
David Boreham 2023-07-05 08:50:56 -06:00
parent 16a812db95
commit 714efe3ddd
3 changed files with 41 additions and 55 deletions

View File

@ -13,45 +13,18 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http:#www.gnu.org/licenses/>.
import click from util import get_yaml
import os
from shutil import copyfile
import sys
from .util import get_stack_config_filename, get_parsed_deployment_spec
default_spec_file_content = """stack: mainnet-laconic default_spec_file_content = """config:
data_dir: /my/path node_moniker: my-node-name
node_name: my-node-name chain_id: my-chain-id
"""
init_help_text = """Add helpful text here on setting config variables.
""" """
def make_default_deployment_dir(): def init(ctx):
return "deployment-001" print(init_help_text)
yaml = get_yaml()
@click.command() return yaml.parse(default_spec_file_content)
@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):
# This function fails with a useful error message if the file doens't exist
parsed_spec = get_parsed_deployment_spec(spec_file)
if ctx.debug:
print(f"parsed spec: {parsed_spec}")
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 and the stack file into the deployment dir
copyfile(spec_file, os.path.join(deployment_dir, os.path.basename(spec_file)))
stack_file = get_stack_config_filename(parsed_spec.stack)
copyfile(stack_file, os.path.join(deployment_dir, os.path.basename(stack_file)))

View File

@ -14,20 +14,12 @@
# 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 util
import os import os
from pathlib import Path from pathlib import Path
from shutil import copyfile, copytree from shutil import copyfile, copytree
import sys import sys
import ruamel.yaml from .util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options, get_yaml
from .util import get_stack_file_path, get_parsed_deployment_spec, get_parsed_stack_config, global_options
def _get_yaml():
# See: https://stackoverflow.com/a/45701840/1701505
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(sequence=3, offset=1)
return yaml
def _make_default_deployment_dir(): def _make_default_deployment_dir():
@ -47,7 +39,7 @@ def _get_named_volumes(stack):
named_volumes = [] named_volumes = []
parsed_stack = get_parsed_stack_config(stack) parsed_stack = get_parsed_stack_config(stack)
pods = parsed_stack["pods"] pods = parsed_stack["pods"]
yaml = _get_yaml() yaml = get_yaml()
for pod in pods: for pod in pods:
pod_file_path = os.path.join(_get_compose_file_dir(), f"docker-compose-{pod}.yml") pod_file_path = os.path.join(_get_compose_file_dir(), f"docker-compose-{pod}.yml")
parsed_pod_file = yaml.load(open(pod_file_path, "r")) parsed_pod_file = yaml.load(open(pod_file_path, "r"))
@ -96,21 +88,34 @@ def _fixup_pod_file(pod, spec, compose_dir):
pod["volumes"][volume] = new_volume_spec pod["volumes"][volume] = new_volume_spec
def call_stack_deploy_init(stack):
# Link with the python file in the stack
# Call a function in it
# If no function found, return None
python_file_path = get_stack_file_path(stack).parent.joinpath("deploy", "commands.py")
spec = util.spec_from_file_location("commands", python_file_path)
imported_stack = util.module_from_spec(spec)
spec.loader.exec_module(imported_stack)
return imported_stack.init()
@click.command() @click.command()
@click.option("--output", required=True, help="Write yaml spec file here") @click.option("--output", required=True, help="Write yaml spec file here")
@click.pass_context @click.pass_context
def init(ctx, output): def init(ctx, output):
yaml = _get_yaml() yaml = get_yaml()
stack = global_options(ctx).stack stack = global_options(ctx).stack
verbose = global_options(ctx).verbose verbose = global_options(ctx).verbose
default_spec_file_content = call_stack_deploy_init(stack)
spec_file_content = {"stack": stack} spec_file_content = {"stack": stack}
spec_file_content.update(default_spec_file_content)
if verbose: if verbose:
print(f"Creating spec file for stack: {stack}") print(f"Creating spec file for stack: {stack}")
named_volumes = _get_named_volumes(stack) named_volumes = _get_named_volumes(stack)
if named_volumes: if named_volumes:
volume_descriptors = {} volume_descriptors = {}
for named_volume in named_volumes: for named_volume in named_volumes:
volume_descriptors[named_volume] = f"../data/{named_volume}" volume_descriptors[named_volume] = f"./data/{named_volume}"
spec_file_content["volumes"] = volume_descriptors spec_file_content["volumes"] = volume_descriptors
with open(output, "w") as output_file: with open(output, "w") as output_file:
yaml.dump(spec_file_content, output_file) yaml.dump(spec_file_content, output_file)
@ -142,7 +147,7 @@ def create(ctx, spec_file, deployment_dir):
destination_compose_dir = os.path.join(deployment_dir, "compose") destination_compose_dir = os.path.join(deployment_dir, "compose")
os.mkdir(destination_compose_dir) os.mkdir(destination_compose_dir)
data_dir = Path(__file__).absolute().parent.joinpath("data") data_dir = Path(__file__).absolute().parent.joinpath("data")
yaml = _get_yaml() yaml = get_yaml()
for pod in pods: for pod in pods:
pod_file_path = os.path.join(_get_compose_file_dir(), f"docker-compose-{pod}.yml") pod_file_path = os.path.join(_get_compose_file_dir(), f"docker-compose-{pod}.yml")
parsed_pod_file = yaml.load(open(pod_file_path, "r")) parsed_pod_file = yaml.load(open(pod_file_path, "r"))

View File

@ -15,7 +15,7 @@
import os.path import os.path
import sys import sys
import yaml import ruamel.yaml
from pathlib import Path from pathlib import Path
@ -42,7 +42,7 @@ def get_parsed_stack_config(stack):
stack_file_path = stack if isinstance(stack, os.PathLike) else get_stack_file_path(stack) stack_file_path = stack if isinstance(stack, os.PathLike) else get_stack_file_path(stack)
try: try:
with stack_file_path: with stack_file_path:
stack_config = yaml.safe_load(open(stack_file_path, "r")) stack_config = get_yaml().load(open(stack_file_path, "r"))
return stack_config return stack_config
except FileNotFoundError as error: except FileNotFoundError as error:
# We try here to generate a useful diagnostic error # We try here to generate a useful diagnostic error
@ -60,7 +60,7 @@ def get_parsed_deployment_spec(spec_file):
spec_file_path = Path(spec_file) spec_file_path = Path(spec_file)
try: try:
with spec_file_path: with spec_file_path:
deploy_spec = yaml.safe_load(open(spec_file_path, "r")) deploy_spec = get_yaml().load(open(spec_file_path, "r"))
return deploy_spec return deploy_spec
except FileNotFoundError as error: except FileNotFoundError as error:
# We try here to generate a useful diagnostic error # We try here to generate a useful diagnostic error
@ -69,6 +69,14 @@ def get_parsed_deployment_spec(spec_file):
sys.exit(1) sys.exit(1)
def get_yaml():
# See: https://stackoverflow.com/a/45701840/1701505
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.indent(sequence=3, offset=1)
return yaml
# TODO: this is fragile wrt to the subcommand depth # TODO: this is fragile wrt to the subcommand depth
# See also: https://github.com/pallets/click/issues/108 # See also: https://github.com/pallets/click/issues/108
def global_options(ctx): def global_options(ctx):