123 lines
3.5 KiB
Bash
Executable File
123 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Project NOMAD Installed Image Capture Helper
|
|
|
|
###################################################################################################################################################################################################
|
|
#
|
|
# Exports the Docker images present on an already-populated Project NOMAD host so
|
|
# they can be added to an offline artifact bundle with:
|
|
#
|
|
# ./build_offline_bundle.sh --extra-image-archive <archive>
|
|
#
|
|
# This transports images only. It does NOT prove that the corresponding Supply
|
|
# Depot apps install offline — their install logic and catalog metadata may have
|
|
# their own network dependencies. See admin/docs/offline-install.md.
|
|
#
|
|
###################################################################################################################################################################################################
|
|
|
|
set -Eeuo pipefail
|
|
|
|
RESET='\033[0m'
|
|
RED='\033[1;31m'
|
|
GREEN='\033[1;32m'
|
|
|
|
OUTPUT_DIR="${PWD}/nomad-image-export"
|
|
INCLUDE_ALL='0'
|
|
|
|
die() {
|
|
echo -e "${RED}#${RESET} $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./capture_installed_images.sh [--output DIR] [--all-local-images]
|
|
|
|
Discovers, by default:
|
|
* images referenced by /opt/project-nomad/compose.yml
|
|
* images used by containers whose names start with "nomad_"
|
|
|
|
Options:
|
|
--output DIR Where to write the archive (default: ./nomad-image-export)
|
|
--all-local-images Also export every tagged image present on this host
|
|
-h, --help Show this help text and exit
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--output)
|
|
[[ $# -ge 2 ]] || die "--output requires a directory."
|
|
OUTPUT_DIR="$2"
|
|
shift
|
|
;;
|
|
--all-local-images)
|
|
INCLUDE_ALL='1'
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
usage >&2
|
|
die "Unknown option: $1"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
command -v docker > /dev/null 2>&1 || die "docker is required."
|
|
mkdir -p "${OUTPUT_DIR}"
|
|
|
|
declare -A seen=()
|
|
images=()
|
|
|
|
add_image() {
|
|
local image="$1"
|
|
[[ -n "${image}" && "${image}" != '<none>:<none>' ]] || return 0
|
|
if [[ -z "${seen[${image}]+set}" ]]; then
|
|
seen["${image}"]='1'
|
|
images+=("${image}")
|
|
fi
|
|
}
|
|
|
|
if [[ -f /opt/project-nomad/compose.yml ]]; then
|
|
while IFS= read -r image; do
|
|
add_image "${image}"
|
|
done < <(docker compose -f /opt/project-nomad/compose.yml config --images 2>/dev/null || true)
|
|
fi
|
|
|
|
while IFS= read -r image; do
|
|
add_image "${image}"
|
|
done < <(docker ps -a --filter 'name=^nomad_' --format '{{.Image}}')
|
|
|
|
if [[ "${INCLUDE_ALL}" == '1' ]]; then
|
|
while IFS= read -r image; do
|
|
add_image "${image}"
|
|
done < <(docker image ls --format '{{.Repository}}:{{.Tag}}')
|
|
fi
|
|
|
|
[[ ${#images[@]} -gt 0 ]] || die "No images were discovered on this host."
|
|
|
|
missing='0'
|
|
for image in "${images[@]}"; do
|
|
if ! docker image inspect "${image}" > /dev/null 2>&1; then
|
|
echo "Image referenced but not present locally: ${image}" >&2
|
|
missing='1'
|
|
fi
|
|
done
|
|
[[ "${missing}" == '0' ]] || die "Every discovered image must exist locally before export."
|
|
|
|
printf '%s\n' "${images[@]}" | sort -u > "${OUTPUT_DIR}/optional-images.txt"
|
|
|
|
docker save -o "${OUTPUT_DIR}/optional-images.tar" "${images[@]}" || die "docker save failed."
|
|
|
|
(cd "${OUTPUT_DIR}" && sha256sum optional-images.txt optional-images.tar > SHA256SUMS)
|
|
|
|
echo ''
|
|
echo -e "${GREEN}#${RESET} Exported ${#images[@]} image(s) to ${OUTPUT_DIR}/optional-images.tar"
|
|
echo ''
|
|
echo "Add to a bundle with:"
|
|
printf ' ./build_offline_bundle.sh --extra-image-archive %q\n' "${OUTPUT_DIR}/optional-images.tar"
|