Debugging and testing Rocks and OCI images (an easy way)

A lot of times, after you build a Rock with rockcraft pack there are a number of steps you have to go through to test it. The problem is, debugging OCI images in general is not without hiccups. And if you have to constantly change something and try again, it can eat a lot of time.

It would be handy to be able to just run this.rock, wouldn’t it?

Why is this an issue?

Sometimes when you pack a rock you just want to make sure it runs, see if some files are there, and so on.

If you don’t know what you’re doing (I was pretty much here):

  1. Push the image to a registry
    • “ahmm I think microk8s has an internal registry I can use or something but then how do I use it”
    • “okay I don’t know let me make a dockerhub repository, so I can push it there”
    • “oh I can use the docker local registry, but I don’t really know what I’m looking at”
  2. Run it
    • “what was the docker command again? history | grep docker
    • “mmmh this is running the image now, but how do I open a shell to it? Let me google it”

Even if you know what you’re doing, it’s annoying to do this if you’re constantly changing small things in the rock.

A somewhat scripty solution: rockcraft-run

I wrote a tiny bash script (called rockcraft-run) that automatically runs all the necessary commands (according to the Rockcraft documentation); the script pushes the image to the local docker registry, runs the image in a container and automatically opens a shell; when closed, the container is also terminated.

Nothing ground-breaking at all, but hey - it saves me quite a bit of time (and frustration)! My workflow went from this:

rockcraft pack
<very long skopeo command>
docker run --rm --detach <rock-name>:<tag-name>
<copy-paste the container id>
docker exec -it <container-id> /bin/bash


rockraft pack && rockcraft-run ./<rock-file>

Here’s the bash script, hope you find it useful! Save it as rockcraft-run somewhere in your $PATH and enjoy :smiling_face:

# rockcraft-run

# Input checks
if [[ $# != 1 ]]; then
  echo "Usage ./rockcraft-run <path/to/rock>"
  exit 1
elif ! which rockcraft >/dev/null; then
  echo "Error: rockcraft is missing; please install it"
  exit 2
elif ! which docker >/dev/null; then
  echo "Error: docker is missing; please install it"
  exit 3
elif ! docker ps >/dev/null; then
  echo "Error: You're lacking docker permissions: run 'newgrp docker'"
  exit 4
elif ! test -f "$1"; then
  echo "Error: The file you're trying to run hasn't been found"
  exit 5

# Parse the variables
rock_path="$(realpath $1)"
rock_file="$(basename $1)"
rock_folder="$(dirname $1)"
rock_name=$(grep -oP -m1 "^name: \K\w+$" "$rock_folder/rockcraft.yaml" || basename "$rock_path" | cut -d'_' -f1)

# Push the image and run it
cd "$rock_folder"
sudo /snap/rockcraft/current/bin/skopeo --insecure-policy copy oci-archive:$rock_file docker-daemon:$rock_name:development >/dev/null
echo "+ $rock_file +"
cd "$current_path"
container_id="$(docker run --rm --detach $rock_name:development)"
docker exec -it $container_id /bin/bash
docker stop $container_id >/dev/null

I used to manually test, for example alertmanager, with the following steps:

tar tf alertmanager_0.24.0_amd64.rock
tar -O -xf alertmanager_0.24.0_amd64.rock oci-layout

skopeo --insecure-policy copy oci-archive:alertmanager_0.24.0_amd64.rock docker-daemon:alertmanager:0.24.0
dive alertmanager:0.24.0

docker run --rm -d -p 9093:9093 alertmanager:0.24.0
curl localhost:9093/api/v1/alerts

I imagine spread tests would be a great alternative.