-
Notifications
You must be signed in to change notification settings - Fork 0
feat(utils) - Utility Scripts for Virtual Machines #1
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| #!/bin/bash | ||
| # Utility functions for managing VM global packages | ||
|
|
||
| function install_conda_globally() { | ||
| local group_owner="${1:-root}" | ||
|
|
||
| # shellcheck disable=SC2155 | ||
| local installer="Miniforge3-$(uname)-$(uname -m).sh" | ||
| curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/$installer" | ||
|
|
||
| sudo bash "$installer" -b -p /opt/conda | ||
|
|
||
| # shellcheck disable=SC2016 | ||
| echo 'export PATH=$PATH:/opt/conda/bin' | sudo tee /etc/profile.d/conda.sh | ||
| sudo chmod +x /etc/profile.d/conda.sh | ||
|
|
||
| sudo tee /opt/conda/.condarc >/dev/null <<'EOF' | ||
| pkgs_dirs: | ||
| - /opt/conda/pkgs | ||
| envs_dirs: | ||
| - ~/scratch/.conda/envs | ||
| auto_activate_base: false | ||
| EOF | ||
|
|
||
| sudo chown -R root:root /opt/conda | ||
| sudo chmod -R a+rX /opt/conda | ||
|
|
||
| sudo mkdir -p /opt/conda/pkgs | ||
| sudo chown -R root:"$group_owner" /opt/conda/pkgs | ||
| sudo chmod -R 2775 /opt/conda/pkgs | ||
|
|
||
| rm -f "$installer" | ||
|
|
||
| echo "Conda installed globally in /opt/conda." | ||
| echo "Shared package cache at /opt/conda/pkgs (group: $group_owner)." | ||
| echo "User environments will default to ~/scratch/.conda/envs." | ||
| echo "Reload your shell or run: source /etc/profile.d/conda.sh" | ||
| } | ||
|
|
||
| function install_pypoetry_globally() { | ||
| local group_owner="${1:-root}" | ||
|
|
||
| local install_dir="/opt/poetry" | ||
| local cache_dir="/opt/poetry/cache" | ||
|
|
||
| if ! command -v python3 >/dev/null 2>&1; then | ||
| echo "Python3 not found. Installing..." | ||
| sudo apt update | ||
| sudo apt install -y python3 python3-venv python3-pip | ||
| fi | ||
|
|
||
| curl -sSL https://install.python-poetry.org | sudo env POETRY_HOME="$install_dir" python3 - | ||
|
|
||
| sudo chown -R root:"$group_owner" "$install_dir" | ||
| sudo chmod -R 755 "$install_dir" | ||
|
|
||
| sudo mkdir -p "$cache_dir" | ||
| sudo chown -R root:"$group_owner" "$cache_dir" | ||
| sudo chmod -R 2775 "$cache_dir" | ||
|
|
||
| sudo tee /etc/profile.d/poetry.sh >/dev/null <<EOF | ||
| export PATH=\$PATH:$install_dir/bin | ||
| export POETRY_CACHE_DIR=$cache_dir | ||
| EOF | ||
| sudo chmod +x /etc/profile.d/poetry.sh | ||
|
|
||
| echo "Poetry installed globally in $install_dir." | ||
| echo "Global Poetry cache: $cache_dir (group: $group_owner)." | ||
| echo "Reload your shell or run: source /etc/profile.d/poetry.sh" | ||
| } | ||
|
|
||
| function install_uv_globally() { | ||
| local group_owner="${1:-root}" | ||
|
|
||
| local install_dir="/opt/uv" | ||
| local cache_dir="/opt/uv/cache" | ||
| local python_install_dir="/opt/uv/python" | ||
| local python_bin_dir="/opt/uv/bin" | ||
|
|
||
| curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR="$install_dir" sh | ||
|
|
||
| sudo chown -R root:"$group_owner" "$install_dir" | ||
| sudo chmod -R 755 "$install_dir" | ||
|
|
||
| sudo mkdir -p "$cache_dir" | ||
| sudo chown -R root:"$group_owner" "$cache_dir" | ||
| sudo chmod -R 2775 "$cache_dir" | ||
|
|
||
| sudo mkdir -p "$python_install_dir" | ||
| sudo chown -R root:"$group_owner" "$python_install_dir" | ||
| sudo chmod -R 2775 "$python_install_dir" | ||
|
|
||
| sudo mkdir -p "$python_bin_dir" | ||
| sudo chown -R root:"$group_owner" "$python_install_dir" | ||
| sudo chmod -R 2775 "$python_install_dir" | ||
|
Comment on lines
+94
to
+95
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be $python_bin_dir? |
||
|
|
||
| sudo tee /etc/profile.d/uv.sh >/dev/null <<EOF | ||
| export PATH=$install_dir:\$PATH | ||
| export UV_CACHE_DIR=$cache_dir | ||
| export UV_PYTHON_INSTALL_DIR=$python_install_dir | ||
| export UV_PYTHON_BIN_DIR=$python_bin_dir | ||
| EOF | ||
| sudo chmod +x /etc/profile.d/uv.sh | ||
|
|
||
| echo "uv installed globally in $install_dir." | ||
| echo "Shared cache: $cache_dir" | ||
| echo "Reload your shell or run: source /etc/profile.d/uv.sh" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,215 @@ | ||
| #!/bin/bash | ||
| # Utility functions for managing VM users | ||
|
|
||
| function delete_user_and_dirs { | ||
| local username="$1"; shift | ||
| local basedir="" | ||
| local force="false" | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --basedir) | ||
| basedir="$2"; | ||
| shift 2 | ||
| ;; | ||
| --force) | ||
| force="true"; | ||
| shift | ||
| ;; | ||
| *) | ||
| echo "Unknown option for delete_user_and_dirs: $1" >&2; exit 1 ;; | ||
| esac | ||
| done | ||
|
|
||
| local userdir="" | ||
| if [[ -n "$basedir" ]]; then | ||
| userdir="$basedir/$username" | ||
| fi | ||
|
|
||
| sudo deluser --remove-home "$username" || true | ||
|
|
||
| if [[ -n "$userdir" && -d "$userdir" ]]; then | ||
|
|
||
| if [[ "$force" == "true" ]]; then | ||
| echo "Force enabled: deleting $userdir" | ||
| sudo rm -rf "$userdir" || true | ||
| else | ||
| echo "Skipping deletion of $userdir (use --force to override)" | ||
| fi | ||
| fi | ||
| } | ||
|
|
||
| function add_user_to_groups() { | ||
| local username="$1"; shift | ||
| local groups=("$@") | ||
|
|
||
| if [ ${#groups[@]} -eq 0 ]; then | ||
| echo "No groups specified for user" | ||
| return 1 | ||
| fi | ||
|
|
||
| for group in "${groups[@]}"; do | ||
| if getent group "$group" >/dev/null; then | ||
| echo "Adding $username to $group..." | ||
| sudo usermod -aG "$group" "$username" | ||
| else | ||
| echo "Group $group does not exist, skipping." | ||
| fi | ||
| done | ||
| } | ||
|
|
||
| function create_user_and_dirs() { | ||
| local username="$1"; shift | ||
| local basedir="" | ||
| local force="false" | ||
| local groups=() | ||
|
|
||
| while [[ $# -gt 0 ]]; do | ||
| case "$1" in | ||
| --basedir) | ||
| basedir="$2"; | ||
| if [[ ! -d "$basedir" ]]; then | ||
| echo "Error: base directory '$basedir' does not exist." | ||
| return 1 | ||
| fi | ||
| shift 2 | ||
| ;; | ||
| --force) | ||
| force="true"; | ||
| shift | ||
| ;; | ||
| --group) | ||
| groups+=("$2") | ||
| shift 2 | ||
| ;; | ||
| *) | ||
| echo "Unknown option for create_user_and_dirs: $1" >&2; exit 1 ;; | ||
| esac | ||
| done | ||
|
|
||
| local userdir="" | ||
| if [[ -n "$basedir" ]]; then | ||
| userdir="$basedir/$username" | ||
|
|
||
| if [[ -d "$userdir" ]]; then | ||
| echo "Error: userdir '$userdir' already exists." | ||
| return 1 | ||
| fi | ||
| fi | ||
|
|
||
| # shellcheck disable=SC2064 | ||
| trap "delete_user_and_dirs '$username' ${basedir:+--basedir \"$basedir\"} ${force:+--force}" ERR | ||
|
|
||
| sudo adduser "$username" | ||
|
|
||
| local homedir | ||
| homedir=$(eval echo "~$username") | ||
|
|
||
| local scratch_link="$homedir/scratch" | ||
| if [[ -e "$scratch_link" || -L "$scratch_link" ]]; then | ||
| sudo rm -rf "$scratch_link" | ||
| fi | ||
|
|
||
| if [[ -n "$userdir" ]]; then | ||
| if [[ -d "$userdir" && "$force" == "true" ]]; then | ||
| sudo rm -rf "$userdir" | ||
| fi | ||
|
|
||
| sudo mkdir -p "$userdir" | ||
| sudo chown -R "$username" "$userdir" | ||
| sudo chmod -R 700 "$userdir" | ||
|
|
||
| sudo ln -s "$userdir" "$scratch_link" | ||
| sudo chown -h "$username:$username" "$scratch_link" | ||
|
|
||
| add_user_to_groups "$username" "${groups[@]}" | ||
|
||
| fi | ||
|
|
||
| trap - ERR | ||
| echo "User '$username' created successfully${userdir:+ with home dir $userdir}" | ||
| } | ||
|
|
||
| function setup_authorized_keys() { | ||
| local username="$1" | ||
| local pubkey="${2:-}" | ||
|
|
||
| local homedir | ||
| homedir=$(eval echo "~$username") | ||
|
|
||
| local sshdir="$homedir/.ssh" | ||
| local authfile="$sshdir/authorized_keys" | ||
|
|
||
| sudo mkdir -p "$sshdir" | ||
| sudo chown "$username:$username" "$sshdir" | ||
| sudo chmod 700 "$sshdir" | ||
|
|
||
| sudo touch "$authfile" | ||
| sudo chown "$username:$username" "$authfile" | ||
| sudo chmod 600 "$authfile" | ||
|
|
||
| if [[ -n "$pubkey" ]]; then | ||
| echo "$pubkey" | sudo tee -a "$authfile" > /dev/null | ||
| sudo chown "$username:$username" "$authfile" | ||
| fi | ||
|
|
||
| echo "authorized_keys set up for $username at $authfile" | ||
| } | ||
|
|
||
| function setup_user_env() { | ||
| local username="$1" | ||
| local userdir="$2" # e.g., /mnt/data/eniyansoro | ||
| local shell_profile | ||
|
|
||
| local homedir | ||
| homedir=$(eval echo "~$username") | ||
|
|
||
| if [[ ! -d "$userdir" ]]; then | ||
| echo "Error: userdir '$userdir' does not exist." | ||
| return 1 | ||
| fi | ||
|
|
||
| # Choose a shell profile to update | ||
| if [[ -f "$homedir/.bashrc" ]]; then | ||
| shell_profile="$homedir/.bashrc" | ||
| else | ||
| shell_profile="$homedir/.profile" | ||
| fi | ||
|
|
||
| sudo bash -c "echo 'export XDG_CACHE_HOME=\"$userdir/.cache\"' >> $shell_profile" | ||
| sudo chown "$username:$username" "$shell_profile" | ||
|
|
||
| sudo mkdir -p "$userdir/.cache" | ||
| sudo chown "$username:$username" "$userdir/.cache" | ||
| sudo chmod 700 "$userdir/.cache" | ||
|
|
||
| echo "Set XDG_CACHE_HOME for $username to $userdir/.cache" | ||
| } | ||
|
|
||
| # ------------------------------------------------------- | ||
| # DEPRECATED: We now set XDG_CACHE_HOME in setup_user_env | ||
| # ------------------------------------------------------- | ||
| # function symlink_user_cache() { | ||
| # local username="$1" | ||
| # local target_basedir="$2" | ||
|
|
||
| # local homedir | ||
| # homedir=$(eval echo "~$username") | ||
|
|
||
| # local target_cache="$target_basedir/.cache" | ||
| # local user_cache="$homedir/.cache" | ||
|
|
||
| # sudo mkdir -p "$target_cache" | ||
| # sudo chown "$username:$username" "$target_cache" | ||
| # sudo chmod 700 "$target_cache" | ||
|
|
||
| # if [[ -e "$user_cache" || -L "$user_cache" ]]; then | ||
| # sudo rm -rf "$user_cache" | ||
| # fi | ||
|
|
||
|
|
||
| # sudo ln -s "$target_cache" "$user_cache" | ||
| # sudo chown -h "$username:$username" "$user_cache" | ||
|
|
||
| # echo "Linked $homedir/.cache -> $target_cache" | ||
| # } | ||
| # ------------------------------------------------------- | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The chown and chmod operations on lines 94-95 should target
$python_bin_dirinstead of$python_install_dir, as the mkdir operation on line 93 creates the$python_bin_dirdirectory.