Skip to content

Commit

Permalink
CLI: Add the subcommand verdi computer export
Browse files Browse the repository at this point in the history
Enables the export of the configuration and setup of a computer to yaml
file similar to `verdi code export`. Since the setup and configuration
are two seperate steps, one has to specify with `config` or `setup`
which of the two should be exported.
  • Loading branch information
agoscinski committed May 14, 2024
1 parent 589a3b2 commit 1b7c3e0
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/source/reference/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Below is a list with all available subcommands.
disable Disable the computer for the given user.
duplicate Duplicate a computer allowing to change some parameters.
enable Enable the computer for the given user.
export Exports the Authinfo details for a computer (and user).
list List all available computers.
relabel Relabel a computer.
setup Create a new computer.
Expand Down
59 changes: 59 additions & 0 deletions src/aiida/cmdline/commands/cmd_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,3 +730,62 @@ def computer_config_show(computer, user, defaults, as_option_string):
else:
table.append((f'* {name}', '-'))
echo_tabulate(table, tablefmt='plain')


@verdi_computer.group('export', cls=LazyConfigureGroup)
def computer_export():
"""Exports the Authinfo details for a computer (and user)."""


@computer_export.command('setup')
@arguments.COMPUTER()
@arguments.OUTPUT_FILE(type=click.Path(exists=False))
@with_dbenv()
def computer_export_setup(computer, output_file):
"""Export computer setup to a yaml file."""
import yaml

computer_setup_data = {
'label': computer.label,
'description': computer.description,
'hostname': computer.hostname,
'transport': computer.transport_type,
'scheduler': computer.scheduler_type,
'work_dir': computer.get_workdir(),
'shebang': computer.get_shebang(),
'mpirun_command': ' '.join(computer.get_mpirun_command()),
'mpiprocs_per_machine': computer.get_default_mpiprocs_per_machine(),
'default_memory_per_machine': computer.get_default_memory_per_machine(),
'prepend_text': computer.get_prepend_text(),
'append_text': computer.get_append_text(),
'use_double_quotes': computer.get_use_double_quotes(),
}
try:
with open(output_file, 'w', encoding='utf-8') as yfhandle:
yaml.dump(computer_setup_data, yfhandle)
echo.echo_success(f"Computer<{computer.pk}> {computer.label} setup exported to file '{output_file}'.")
except Exception:
raise


@computer_export.command('config')
@arguments.COMPUTER()
@arguments.OUTPUT_FILE(type=click.Path(exists=False))
@with_dbenv()
def computer_export_config(computer, output_file):
"""Export computer configuration to a yaml file."""
import yaml

if not computer.is_configured:
echo.echo_error(
f'Computer<{computer.pk}> {computer.label} config cannot be exported,'
'because computer has not been configured yet.'
)
else:
computer_config_data = computer.get_configuration()
try:
with open(output_file, 'w', encoding='utf-8') as yfhandle:
yaml.dump(computer_config_data, yfhandle)
echo.echo_success(f"Computer<{computer.pk}> {computer.label} config exported to file '{output_file}'.")
except Exception:
raise
67 changes: 67 additions & 0 deletions tests/cmdline/commands/test_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
from collections import OrderedDict

import pytest
import yaml
from aiida import orm
from aiida.cmdline.commands.cmd_computer import (
computer_configure,
computer_delete,
computer_duplicate,
computer_export_config,
computer_export_setup,
computer_list,
computer_relabel,
computer_setup,
Expand Down Expand Up @@ -511,6 +514,70 @@ def test_show(self):
assert '--username=' in result.output
assert result_cur.output == result.output

def test_computer_export_setup(self):
"""Test if 'verdi computer export setup' command works"""
self.comp_builder.label = 'test_computer_export_setup'
self.comp_builder.transport = 'core.ssh'
comp = self.comp_builder.new()
comp.store()

exported_setup_filename = 'computer-setup.yml'
try:
result = self.cli_runner(computer_export_setup, [comp.label, exported_setup_filename])
assert 'Success' in result.output, 'Command should have run successfull.'
assert (
f'{exported_setup_filename}' in result.output
), 'Filename should be in terminal output but was not found.'
assert os.path.exists(
exported_setup_filename
), f"'{exported_setup_filename}' was not created during export."

# verifying correctness by comparing internal and loaded yml object
with open(exported_setup_filename, 'r', encoding='utf-8') as yfhandle:
configure_setup_data = yaml.safe_load(yfhandle)
assert configure_setup_data == self.comp_builder.get_computer_spec(
comp
), 'Internal computer configuration does not agree with exported one.'
except Exception:
raise
finally:
if os.path.exists(exported_setup_filename):
os.remove(exported_setup_filename)

def test_computer_export_config(self):
"""Test if 'verdi computer export config' command works"""
self.comp_builder.label = 'test_computer_export_config'
self.comp_builder.transport = 'core.ssh'
comp = self.comp_builder.new()
comp.store()

exported_config_filename = 'computer-configure.yml'
try:
result = self.cli_runner(computer_export_config, [comp.label, exported_config_filename])
assert 'Error' in result.output, 'Command should have raised an error.'

comp.configure(safe_interval=0.0)
result = self.cli_runner(computer_export_config, [comp.label, exported_config_filename])
assert 'Success' in result.output, 'Command should have run successfull.'
assert (
f'{exported_config_filename}' in result.output
), 'Filename should be in terminal output but was not found.'
assert os.path.exists(
exported_config_filename
), f"'{exported_config_filename}' was not created during export."

# verifying correctness by comparing internal and loaded yml object
with open(exported_config_filename, 'r', encoding='utf-8') as yfhandle:
configure_config_data = yaml.safe_load(yfhandle)
assert (
configure_config_data == comp.get_configuration()
), 'Internal computer configuration does not agree with exported one.'
except Exception:
raise
finally:
if os.path.exists(exported_config_filename):
os.remove(exported_config_filename)


class TestVerdiComputerCommands:
"""Testing verdi computer commands.
Expand Down

0 comments on commit 1b7c3e0

Please sign in to comment.