jrb

Hamburg - Advent of Sysadmin 2025 - 12/06

6 décembre 2025

This is part of Sad Servers' Advent of Sysadmin 2025 series.

I'm doing each challenge every day and I'm publishing a quick write up for each one every day.

12-06: JQ filtering

Spoiler alert! This gives the solution to the challenge.
If you want to do it on your own, stop reading.


Scenario: "Hamburg": Find the AWS EC2 volume

Level: Easy

Description: We have a lot of AWS EC2 instances and EBS volumes, the description of which volumes we have saved to a file with: aws ec2 describe-volumes > aws-volumes.json.
One of the volumes attached to an ec2 instance contains important data and we need to identify which instance is attached to (its ID), but we only remember these characteristics: gp3, created before 31/09/2025 , Size < 64 , Iops < 1500, Throughput > 300.

Find the correct instance and put its "InstanceId" into the ~/mysolution file, e.g.: echo "i-00000000000000000" > ~/mysolution

Test: Running md5sum /home/admin/mysolution returns e7e34463823bf7e39358bf6bb24336d8 (we also accept the file without a new line at the end).

The "Check My Solution" button runs the script /home/admin/agent/check.sh, which you can see and execute.

Time to Solve: 30 minutes.

OS: Debian 13

Root (sudo) Access: Yes


Just by reading the challenge description, I knew I had to work with jq to find the answer.

Before launching the challenge, I started by reading the output structure of the AWS CLI describe-volumes command here: describe-volumes — AWS CLI 2.32.11 Command Reference

I ended up preparing my jq filter like this to match the search criteria:

  • VolumeType == gp3
  • CreateTime < 2025-09-31T00:00:002
  • Size < 64
  • Iops < 1500
  • Throughput > 300
jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002")'
cat aws-volumes.json | jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002")'
{
  "AvailabilityZoneId": "use2-az2",
  "Iops": 1000,
  "VolumeType": "gp3",
  "MultiAttachEnabled": false,
  "Throughput": 500,
  "Operator": {
    "Managed": false
  },
  "VolumeId": "vol-29d115ef9c3944f29",
  "Size": 8,
  "SnapshotId": "snap-4d14b6dc50854a9cb",
  "AvailabilityZone": "us-east-2c",
  "State": "in-use",
  "CreateTime": "2025-09-29T16:43:18.004823Z",
  "Attachments": [
    {
      "DeleteOnTermination": true,
      "VolumeId": "vol-29d115ef9c3944f29",
      "InstanceId": "i-371822c092b2470da",
      "Device": "/dev/xvdc",
      "State": "attached",
      "AttachTime": "2025-09-29T17:41:18.004823Z"
    }
  ],
  "Encrypted": false
}
{
  "AvailabilityZoneId": "use2-az3",
  "Iops": 1000,
  "VolumeType": "gp3",
  "MultiAttachEnabled": false,
  "Throughput": 500,
  "Operator": {
    "Managed": false
  },
  "VolumeId": "vol-99646e602c6e4b92a",
  "Size": 16,
  "SnapshotId": "snap-27b0fb199d294889b",
  "AvailabilityZone": "us-east-2a",
  "State": "available",
  "CreateTime": "2025-09-29T01:21:18.004823Z",
  "Attachments": [],
  "Encrypted": false
}

I confirmed this command was working as expected. And then, I had to select the attachment instance ID to get the answer:

cat aws-volumes.json | jq '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002") | .Attachments[].InstanceId'

Redirect that into the file mysolution with the --raw-output argument for jq. And that's it!

cat aws-volumes.json | jq --raw-output '.Volumes[] | select(.VolumeType == "gp3" and .Size < 64 and .Iops < 1500 and .Throughput > 300 and .CreateTime < "2025-09-31T00:00:002") | .Attachments[].InstanceId' > mysolution

A quick and easy one! 🚩