Skip to content

Commit

Permalink
Add helpers for creating VMs
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackenmen committed Mar 30, 2024
1 parent f73f7dd commit 1780488
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 3 deletions.
57 changes: 54 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ A few *little* scripts for things I do often so that I can type less
or make fewer clicks.\
I'm just a bit lazy...

Only tested on Windows.\
`git-` scripts are Bash scripts so they should work on Unix systems as well,
but the AutoHotkey and Batch scripts will obviously only work on Windows.
Scripts that aren't OS-specific (`bin/virt-*`, `bin/*.cmd`, `ahk_scripts/*`) have been tested on Linux and Windows.\
`bin/virt-*` scripts are Linux-specific and require `libvirt` and `virtinst` packages.\
`bin/*.cmd` and `ahk_scripts/*` scripts are Windows-specific.

## Usage/Installation

Expand Down Expand Up @@ -111,6 +111,57 @@ before all other branches. This is meant to make it easier to find *your* recent
Each entry on the branch list takes two lines which, while making it less concise,
allows it to show more of the commit message and is, arguably, more readable.

### vm-run

This scripts run a temporary VM with the given Linux image.

Image's default user is set up with the `~/.ssh/id_rsa` key and additionally,
`vm` user with `vm` password and the aforementioned key is also created.

See documentation of `vm-image-add` for details about image management.

Usage: `vm-run <image_name>`

The domain (VM) name will be set to `tmp-<image_name>`, optionally suffixed with
a number (`tmp-<image_name>-2`) when a machine with same name exists.

### vm-connect

Connect to a VM created by `vm-run` or `libvirt`.

In case of VMs created by `vm-run`, `<vm_name>` is equivalent to image name
with a `tmp-` prefix and an optional `-N` suffix when multiple VMs with same name
are running at the same time, e.g. `tmp-ubuntu2204` or `tmp-ubuntu2204-2`.

Usage: `vm-connect <vm_name>`

### vm-image-add

Add a Linux VM image for use by `vm-run`.

Usage: `vm-image-add <image_name> <sums_url> <sum_type> <filename_pattern>`

The script expects to be able to download a Linux image based on
a provided `CHECKSUMS` file in a format returned by `sha256sum`/`sha512sum` program
ran with or without `--tag` option. `<filename_pattern>` is used to extract
the relevant checksum. This setup is generally supported by the data that is provided
by the distro maintainers though there are 2 notable outliers:
- Red Hat Enterprise Linux - requires subscription
- Oracle Linux - does not provide checksum file in a parsable format

You can find examples for different distros at:
https://github.com/Jackenmen/dotfiles/tree/main/private_dot_config/little-helpers-vm-images

### vm-image-fetch

Fetch latest Linux VM image (added through `vm-image-add`) with the given name.

This tool is typically invoked automatically.

Usage: `vm-image-fetch [-f] <image_name>`

Without the `-f` flag, the image only gets fetched when it isn't already in cache.

## Available AHK scripts (`ahk_scripts/` directory)

### win_terminal_hotkeys
Expand Down
40 changes: 40 additions & 0 deletions bin/vm-connect
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/usr/bin/bash
#
# Connect to a VM created by `vm-run` or `libvirt`.
#
# In case of VMs created by `vm-run`, `<vm_name>` is equivalent to image name
# with a `tmp-` prefix and an optional `-N` suffix when multiple VMs with same name
# are running at the same time, e.g. `tmp-ubuntu2204` or `tmp-ubuntu2204-2`.
#
# Usage: `vm-connect <vm_name>`
#
#
# Copyright 2024 Jakub Kuczys (https://github.com/Jackenmen)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -eo pipefail

help() {
echo 'Usage: vm-connect <vm_name>'
}

vm_name=$1
if [[ -z "$vm_name" ]]; then
help
exit 2
fi

vm_ip=$(virsh domifaddr "$vm_name" | awk -F'[ /]+' '/^[[:blank:]]vnet/ {print $5}' | head -1)

ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "vm@$vm_ip"
83 changes: 83 additions & 0 deletions bin/vm-image-add
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/bin/bash
#
# Add a Linux VM image for use by `vm-run`.
#
# Usage: `vm-image-add <image_name> <sums_url> <sum_type> <filename_pattern>`
#
# The script expects to be able to download a Linux image based on
# a provided `CHECKSUMS` file in a format returned by `sha256sum`/`sha512sum` program
# ran with or without `--tag` option. `<filename_pattern>` is used to extract
# the relevant checksum. This setup is generally supported by the data that is provided
# by the distro maintainers though there are 2 notable outliers:
# - Red Hat Enterprise Linux - requires subscription
# - Oracle Linux - does not provide checksum file in a parsable format
#
# You can find examples for different distros at:
# https://github.com/Jackenmen/dotfiles/tree/main/private_dot_config/little-helpers-vm-images
#
#
# Copyright 2024 Jakub Kuczys (https://github.com/Jackenmen)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -eo pipefail

help() {
echo 'Usage: vm-image-add <image_name> <sums_url> <sum_type> <filename_pattern>'
}

image_name=$1
if [[ -z "$image_name" ]]; then
help
exit 2
fi
sums_url=$2
if [[ -z "$sums_url" ]]; then
help
exit 2
fi
sum_type=$3
if [[ -z "$sum_type" ]]; then
help
exit 2
fi
filename_pattern=$4
if [[ -z "$filename_pattern" ]]; then
help
exit 2
fi

image_cfg_dir="${XDG_CONFIG_HOME:-$HOME/.config}/little-helpers-vm-images"
mkdir -p "$image_cfg_dir"
image_file="$image_cfg_dir/$image_name"
if [[ -e "$image_file" ]]; then
echo 'Image with this name already exists:'
echo "- Image name: $(sed '1q;d' "$image_file")"
echo "- Checksums file URL: $(sed '2q;d' "$image_file")"
echo "- Checksum type: $(sed '3q;d' "$image_file")"
echo "- Filename pattern: $(sed '4q;d' "$image_file")"
exit 1
fi

{
echo "$image_name"
echo "$sums_url"
echo "$sum_type"
echo "$filename_pattern"
} > "$image_file"

if ! vm-image-fetch "$image_name"; then
exit_code=$?
rm "$image_file"
exit "$exit_code"
fi
99 changes: 99 additions & 0 deletions bin/vm-image-fetch
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/bash
#
# Fetch latest Linux VM image (added through `vm-image-add`) with the given name.
#
# This tool is typically invoked automatically.
#
# Usage: `vm-image-fetch [-f] <image_name>`
#
# Without the `-f` flag, the image only gets fetched when it isn't already in cache.
#
#
# Copyright 2024 Jakub Kuczys (https://github.com/Jackenmen)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -eo pipefail

help() {
echo 'Usage: vm-image-fetch [-f] <image_name>'
}

force_download=0
OPTIND=1
while getopts 'f' flag; do
case "$flag" in
f)
force_download=1
;;
*)
help
exit 2
;;
esac
done
shift "$((OPTIND-1))"

image_name=$1
if [[ -z "$image_name" ]]; then
help
exit 2
fi

image_cfg_dir="${XDG_CONFIG_HOME:-$HOME/.config}/little-helpers-vm-images"
image_file="$image_cfg_dir/$image_name"
if [[ ! -f "$image_file" ]]; then
echo 'ERROR: Image with this name does not exist!'
exit 2
fi

sums_url=$(sed '2q;d' "$image_file")
if [[ -z "$sums_url" ]]; then
if [[ ! -f "$image_file" ]]; then
echo 'ERROR: No sum URL set but the image does not already exist.'
exit 1
fi
echo 'Using cached image as no sums URL is defined.'
exit 0
fi

sum_type=$(sed '3q;d' "$image_file")
filename_pattern=$(sed '4q;d' "$image_file")

checksums=$(curl -L "$sums_url")
checksums+=$(echo '' && echo "$checksums" | sed -nE "s/^${sum_type^^} \(($filename_pattern)\) = ([^ \t]+)\$/\2 \1/p")
matching_files=$(echo "$checksums" | grep -P "^[^ \t]+[ \t]+\*?$filename_pattern\$")
if [[ "$(echo "$matching_files" | wc -l)" -ne 1 ]]; then
echo 'ERROR: Expected only one filename to match but got these matches instead:'
echo "$matching_files"
exit 1
fi

base_url="${sums_url%/*}"
new_checksum=$(echo "$matching_files" | awk '{print $1}')
filename=$(echo "$matching_files" | awk '{print $2}')
filename="${filename#\*}"
image_url="$base_url/$filename"

cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/little-helpers-vm-images"
mkdir -p "$cache_dir"
old_checksum=$( (cat "$cache_dir/$image_name.${sum_type}sum" 2>/dev/null || echo '') | awk '{print $1}' )

if [[ "$force_download" -eq 1 || "$old_checksum" != "$new_checksum" ]]; then
echo 'Downloading new version of the image...'
wget -O "$cache_dir/$image_name.img" "$image_url"
echo "$new_checksum $image_name.img" > "$cache_dir/$image_name.${sum_type}sum"
echo 'Image downloaded and cached.'
else
echo 'Cached image already up-to-date.'
fi
Loading

0 comments on commit 1780488

Please sign in to comment.