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

#492 #493

Merged
merged 22 commits into from
Jul 24, 2024
Merged

#492 #493

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
97 changes: 95 additions & 2 deletions garden_ai/app/hpc_notebook.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import logging
import typer
import os
import subprocess
import tempfile
import sys

logger = logging.getLogger()

Expand All @@ -12,13 +16,102 @@ def hpc_notebook():
pass


def start_apptainer(notebooks_dir, container_image):
process = None
try:
with tempfile.TemporaryDirectory() as working_directory:
tmp_dir = os.path.join(working_directory, "tmp")
os.makedirs(tmp_dir, exist_ok=True)

# Step 2: Set environment variables
os.environ["SINGULARITY_TMPDIR"] = tmp_dir
os.environ["APPTAINER_TMPDIR"] = tmp_dir
os.environ["JUPYTER_RUNTIME_DIR"] = tmp_dir
os.environ["JUPYTER_DATA_DIR"] = tmp_dir
os.environ["JUPYTER_CONFIG_DIR"] = tmp_dir

run_command = [
"apptainer",
"run",
"--bind",
f"{notebooks_dir}:/notebooks",
container_image,
"jupyter",
"notebook",
"--no-browser",
"--ip=0.0.0.0",
]
process = subprocess.Popen(run_command)
process.wait()
logger.info(
"Jupyter Notebook started successfully in the Apptainer container."
)
except KeyboardInterrupt:
if process:
process.terminate()
process.wait()
logger.info("Operation cancelled by user (Ctrl-C).")
typer.echo("Operation cancelled by user (Ctrl-C).")
sys.exit(0)


@hpc_notebook_app.command()
def start():
def rerun(container_image: str = "hpc-notebook.sif"):
current_directory = os.getcwd()
notebooks_dir = os.path.join(current_directory, "notebooks")

if not os.path.exists(container_image):
logger.error("Not found.")
typer.echo("Not found")
else:
start_apptainer(notebooks_dir, container_image)


@hpc_notebook_app.command()
def start(container_image: str = "hpc-notebook.sif"):
"""Open a notebook file in HPC."""
print("🚧🌱🚧 Under Construction 🚧🌱🚧")

# Get the absolute path of the definition file located three levels up from the current script's directory
definition_file = os.path.abspath(
os.path.join(os.path.dirname(__file__), "../../../scripts/Singularity.def")
)

current_directory = os.getcwd()
notebooks_dir = os.path.join(current_directory, "notebooks")

os.makedirs(notebooks_dir, exist_ok=True)

try:
# Ensure the definition file exists
if not os.path.isfile(definition_file):
logger.error(f"Definition file {definition_file} not found.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this approach rely on the user being in the root directory of the project where Singularity.def is? Let's make sure the user can run this command in any directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

typer.echo(f"🚧🌱🚧 Definition file {definition_file} not found 🚧🌱🚧")
raise typer.Exit(code=1)

# Step 3: Build the Apptainer container
build_command = ["apptainer", "build", container_image, definition_file]
subprocess.run(build_command, check=True)
logger.info("Apptainer container built successfully.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this command give you a way to reuse an image if you've already built it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I add a rerun command


# Step 4: Run the Apptainer container and start Jupyter Notebook
start_apptainer(notebooks_dir, container_image)
except subprocess.CalledProcessError as e:
logger.error(f"Failed to start Jupyter Notebook: {e}")
typer.echo("🚧🌱🚧 Failed to start Jupyter Notebook 🚧🌱🚧")
except KeyboardInterrupt:
logger.info("Operation cancelled by user (Ctrl-C).")
typer.echo("Operation cancelled by user (Ctrl-C).")
sys.exit(0)
except Exception as e:
logger.error(f"An error occurred: {e}")
typer.echo("🚧🌱🚧 An unexpected error occurred 🚧🌱🚧")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How should the user shut down their Singularity container when they're done? It's ok to not build in really robust cleanup handling right now, but ideally we could handle the happy path of the user hitting ctrl-c. Or at least we should print instructions to the user for how they can manually end their session.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JoeyC12 Can you address this question?



@hpc_notebook_app.command()
def publish():
"""Publish your hpc-notebook."""
print("🚧🌱🚧 Under Construction 🚧🌱🚧")


if __name__ == "__main__":
hpc_notebook_app()
25 changes: 25 additions & 0 deletions scripts/Singularity.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Bootstrap: docker
From: python:3.8-slim

%post
# install Jupyter Notebook
apt-get update && apt-get install -y \
python3-pip

pip install jupyter

# create notebook directory
mkdir /notebooks

%environment

export PATH=/usr/local/bin:$PATH
export HOME=/root

%runscript

jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser

%startscript

exec /bin/bash -c "jupyter notebook --notebook-dir=/notebooks --ip 0.0.0.0 --no-browser"
Loading