Skip to content

Instantly share code, notes, and snippets.

@nogweii
Last active September 2, 2022 08:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nogweii/0d9afa8246525d21eaf71ad2d12ae955 to your computer and use it in GitHub Desktop.
Save nogweii/0d9afa8246525d21eaf71ad2d12ae955 to your computer and use it in GitHub Desktop.
Easily upload the latest Arch Linux cloudimg to UpCloud
-----BEGIN PGP PUBLIC KEY BLOCK-----
mDMEYpOJrBYJKwYBBAHaRw8BAQdAcSZilBvR58s6aD2qgsDE7WpvHQR2R5exQhNQ
yuILsTq0JWFyY2gtYm94ZXMgPGFyY2gtYm94ZXNAYXJjaGxpbnV4Lm9yZz6IkAQT
FggAOBYhBBuaFphKToy0SHEtKuC3i/QybG+PBQJik4msAhsBBQsJCAcCBhUKCQgL
AgQWAgMBAh4BAheAAAoJEOC3i/QybG+P81YA/A7HUftMGpzlJrPYBFPqW0nFIh7m
sIZ5yXxh7cTgqtJ7AQDFKSrulrsDa6hsqmEC11PWhv1VN6i9wfRvb1FwQPF6D7gz
BGKTiecWCSsGAQQB2kcPAQEHQBzLxT2+CwumKUtfi9UEXMMx/oGgpjsgp2ehYPBM
N8ejiPUEGBYIACYWIQQbmhaYSk6MtEhxLSrgt4v0MmxvjwUCYpOJ5wIbAgUJCWYB
gACBCRDgt4v0Mmxvj3YgBBkWCAAdFiEEZW5MWsHMO4blOdl+NDY1poWakXQFAmKT
iecACgkQNDY1poWakXTwaQEAwymt4PgXltHUH8GVUB6Xu7Gb5o6LwV9fNQJc1CMl
7CABAJw0We0w1q78cJ8uWiomE1MHdRxsuqbuqtsCn2Dn6/0Cj+4A/Apcqm7uzFam
pA5u9yvz1VJBWZY1PRBICBFSkuRtacUCAQC7YNurPPoWDyjiJPrf0Vzaz8UtKp0q
BSF/a3EoocLnCA==
=APeC
-----END PGP PUBLIC KEY BLOCK-----
#!/bin/bash
# Copyright 2022, Nogweii
# SPDX-License-Identifier: MIT
set -euo 'pipefail'
# Components of the URLs to download the arch box (cloud version)
arch_box_url_prefix="https://geo.mirror.pkgbuild.com/images/"
arch_box_version="latest"
files=("Arch-Linux-x86_64-cloudimg.qcow2.SHA256" "Arch-Linux-x86_64-cloudimg.qcow2.sig" "Arch-Linux-x86_64-cloudimg.qcow2")
# Download the file, but don't retry downloading it again if it's up-to-date
for file in "${files[@]}"; do
echo "Downloading ${file}..."
curl -fsS --remote-time "${arch_box_url_prefix}/${arch_box_version}/${file}" -o $file -z $file
done
# Check the sha256 checksum
if sha256sum -c --quiet ./Arch-Linux-x86_64-cloudimg.qcow2.SHA256; then
echo "SHA256: OK!"
else
echo "SHA256: Not OK!"
exit 2
fi
# Verify the PGP using the Sequoia tools. `pacman -S sequoia` to install them.
if sqop verify Arch-Linux-x86_64-cloudimg.qcow2.sig arch_box_pubkey.txt < Arch-Linux-x86_64-cloudimg.qcow2 > /dev/null; then
echo "PGP signature: OK!"
else
echo "PGP signature: Not OK!"
exit 2
fi
# Get the version number by quickly searching through the directory listing HTML
curl -sS --remote-time "${arch_box_url_prefix}/${arch_box_version}/" | ruby -ne 'puts $1 if $_ =~ /Arch-Linux-x86_64-cloudimg-(\d+\.\d+)\.qcow2"/' > Arch-Linux-x86_64-cloudimg.version.txt
# Here's an example on how to use the created template in Terraform:
terraform {
required_providers {
upcloud = {
source = "UpCloudLtd/upcloud"
version = "2.5.0"
}
}
}
provider "upcloud" {
# environment variables $UPCLOUD_USERNAME & $UPCLOUD_PASSWORD are required
}
data "upcloud_storage" "arch_template" {
type = "template"
name_regex = "^Arch Linux v.*"
most_recent = true
}
locals {
my_user_data = yamlencode({
runcmd = [
"touch /runcmd_successful",
"echo 'whatever you want'",
],
users = [
"default",
{
name = "my-user"
ssh_authorized_keys = [file("~/.ssh/id_rsa.pub")]
sudo = "ALL=(ALL) NOPASSWD:ALL"
}
]
})
}
resource "upcloud_server" "example" {
hostname = "arch.upcloud.example.com"
zone = data.upcloud_storage.arch_template.zone
user_data = "#cloud-config\n${local.my_user_data}"
title = "this is my example arch linux box"
plan = "1xCPU-1GB"
metadata = true
network_interface {
type = "public"
ip_address_family = "IPv4"
}
network_interface {
type = "public"
ip_address_family = "IPv6"
}
template {
storage = data.upcloud_storage.arch_template.id
filesystem_autoresize = true
delete_autoresize_backup = true
size = 25
}
# If a new Arch template is uploaded, don't try replacing the server with a
# new HDD based off it.
lifecycle {
ignore_changes = [template[0].storage]
}
}

Just run ./upload_to_upcloud.sh and it'll download the latest qcow2 image, then upload the raw version to UpCloud as a template.

It's smart, too. It won't needlessly redownload the latest image if it doesn't need to, nor will it upload it to UpCloud if it exists already in your account.

Dependencies

You'll need a few tools:

  • sqop for verify the PGP signature
  • ruby for extracting the version number out of the HTML
  • upcloud-cli for interacting with UpCloud's API
  • curl for downloading the
  • coreutils for bash and sha256sum
  • qemu-img for converting from qcow2 to raw
  • jq for processing the JSON from UpCloud's API
#!/bin/bash
# Copyright 2022, Nogweii
# SPDX-License-Identifier: MIT
set -euo 'pipefail'
./download_arch_box.sh
version="v$(cat ./Arch-Linux-x86_64-cloudimg.version.txt)"
raw_title="Raw Arch Linux ${version}"
template_title="Arch Linux ${version}"
zone='us-chi1'
# Bail early if there is a template already
existing_template_uuid=$(upctl storage list --template -o json | jq -r ".[] | select(.title == \"${template_title}\") | .uuid")
if [ -n "${existing_template_uuid}" ]; then
echo "Already exists! Use this template:"
upctl storage show $existing_template_uuid
exit 0
fi
# Block execution until the storage device in UpCloud is online
# $1 [string] The UUID of the storage device
function wait_for_storage() {
storage_uuid="${1}"
while [ "$(upctl storage show $storage_uuid -o json | jq -r '.state')" != 'online' ]; do
sleep 1
done
}
# Convert the image from qcow2 (qemu's compressed format) to a raw disk image
qemu-img convert Arch-Linux-x86_64-cloudimg.qcow2 Arch-Linux-x86_64-cloudimg.raw
# Uplaod the raw disk image to UpCloud, which is imported as a disk image
upctl storage import --source-location ./Arch-Linux-x86_64-cloudimg.raw --title "${raw_title}" --zone $zone -o json --force-colours > storage-import.json
raw_uuid=$(jq -r ".uuid" < storage-import.json)
wait_for_storage $raw_uuid
# Convert the raw disk image into a template in UpCloud
upctl storage templatise "${raw_uuid}" --title "${template_title}" -o json --force-colours > storage-template.json
template_uuid=$(jq -r ".uuid" < storage-template.json)
wait_for_storage $template_uuid
# Delete the raw disk, don't need it any more
wait_for_storage $raw_uuid
upctl storage delete "${raw_uuid}"
# and clean up the json files generated
rm storage-import.json storage-template.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment