Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Implement profile reset. #66

Merged
merged 1 commit into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 65 additions & 1 deletion aiidalab_launch/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import socket
from dataclasses import dataclass, field
from pathlib import Path
from shutil import rmtree
from textwrap import wrap

import click
Expand All @@ -25,7 +26,13 @@
Config,
Profile,
)
from .util import get_docker_client, get_latest_version, spinner, webbrowser_available
from .util import (
confirm_with_value,
get_docker_client,
get_latest_version,
spinner,
webbrowser_available,
)
from .version import __version__

MSG_MOUNT_POINT_CONFLICT = """Warning: There is at least one other running
Expand Down Expand Up @@ -638,5 +645,62 @@ def exec(ctx, profile, cmd, privileged, forward_exit_code, wait):
ctx.fail(f"Command failed with exit code: {result['ExitCode']}")


@cli.command()
@click.option(
"--apps",
is_flag=True,
help="Only remove installed apps. The default apps will be installed on the next instance start.",
)
@click.option("--yes", is_flag=True, help="Do not ask for confirmation.")
@with_profile
@pass_app_state
def reset(app_state, profile, apps, yes):
"""Reset an AiiDAlab instance."""
# Check (and abort) in case that the instance is running.
instance = AiidaLabInstance(client=app_state.docker_client, profile=profile)
status = asyncio.run(instance.status())
if status not in (
instance.AiidaLabInstanceStatus.DOWN,
instance.AiidaLabInstanceStatus.CREATED,
instance.AiidaLabInstanceStatus.EXITED,
):
raise click.ClickException(
f"The instance associated with profile '{profile.name}' "
"is still running. Please stop it prior to reset."
)

click.secho(
f"Resetting instance for profile '{profile.name}'. This action cannot be undone!",
err=True,
fg="red",
)

if not yes:
confirm_with_value(
profile.name, "Please enter the name of the profile to continue", abort=True
)

def rmtree_(path: Path) -> None:
if path.exists():
try:
rmtree(path)
except Exception as error:
raise click.ClickException(
f"Encountered error while trying to remove '{path}': {error}"
)

if apps:
click.echo(
"Removing apps directory. Default apps will be installed on next start."
)
rmtree_(Path(profile.home_dir) / "apps")
else:
click.echo("Removing container and associated volumes.")
instance.remove()

click.echo(f"Removing home directory '{profile.home_mount}'.")
rmtree_(Path(profile.home_mount))


if __name__ == "__main__":
cli()
7 changes: 1 addition & 6 deletions aiidalab_launch/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,10 @@ def stop(self, timeout: Optional[float] = None) -> None:
raise RuntimeError("no container")

def remove(self) -> None:
self._requires_container()
assert self.container is not None

# Remove container
try:
if self.container:
self.container.remove()
self._container = None
except AttributeError:
raise RuntimeError("no container")

# Remove conda volume
try:
Expand Down
9 changes: 9 additions & 0 deletions aiidalab_launch/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,12 @@ def get_latest_version(timeout: float = 0.1) -> Optional[Version]:
except OSError as error:
logging.debug(f"Error while requesting latest version: {error}")
return None


def confirm_with_value(value: str, text: str, abort: bool = False) -> bool:
if click.prompt(text, default="", show_default=False) == value:
return True
elif abort:
raise click.Abort
else:
return False