Mounting QCOW2 Images

I use Vagrant for provisioning VMs via libvirt: it’s low-overhead and needs no special non-native software (unlike VirtualBox which I used before, and VMWare WorkStation before that).

My previous PC which ran my Vagrant-built VMs broke though: it does not power on anymore. So I wanted to get the latest files off those. My last backup was 2 months old. Not a big deal, but annoying, and since I could put the mSATA SSD into an external USB case, I could read the data, but mounting QCOW2 images is not as easy as loop-mounting a disk image.

So long story short: this is how to mount a QCOW2 image:

root@giga:/vm/images# file *
debian-VAGRANTSLASH-buster64_vagrant_box_image_10.4.0.img:        QEMU QCOW2 Image (v3), 20000000000 bytes
k3s_knode6.img:                                                   QEMU QCOW2 Image (v2), has backing file (path /var/lib/libvirt/images/debian-VAGRANTSLASH-buster64_vagrant_box_image_10.4.0.img), 21474836480 bytes
root@giga:/vm/images# guestmount -a k3s_knode6.img -m /dev/sda1 /mnt/

Make sure you got the backing file in place.

jq and jc: JSON in the shell

Everyone knows jq: it’s the JSON parser which can do nifty things like picking out data from a JSON document.

The problem is that many commands to not output JSON. E.g. the df command. Or pretty much any normal shell command. kubectl being one of the exceptions.

So what can we do about this? Re-implement all tools! But that’s a lot of work…

Or we use jc! Then you can do things like:

(venv) harald@r2s1:~$ ping 192.168.21.1 -c 4 | jc --ping | jq
{
  "destination_ip": "192.168.21.1",
  "data_bytes": 56,
  "pattern": null,
  "destination": "192.168.21.1",
  "packets_transmitted": 4,
  "packets_received": 4,
  "packet_loss_percent": 0,
  "duplicates": 0,
  "time_ms": 3005,
  "round_trip_ms_min": 1,
  "round_trip_ms_avg": 1.337,
  "round_trip_ms_max": 1.663,
  "round_trip_ms_stddev": 0.241,
  "responses": [
    {
      "type": "reply",
      "timestamp": null,
      "bytes": 64,
      "response_ip": "192.168.21.1",
      "icmp_seq": 1,
      "ttl": 64,
      "time_ms": 1.26,
      "duplicate": false
    },
    {
      "type": "reply",
      "timestamp": null,
      "bytes": 64,
      "response_ip": "192.168.21.1",
      "icmp_seq": 2,
      "ttl": 64,
      "time_ms": 1.43,
      "duplicate": false
    },
    {
      "type": "reply",
      "timestamp": null,
      "bytes": 64,
      "response_ip": "192.168.21.1",
      "icmp_seq": 3,
      "ttl": 64,
      "time_ms": 1,
      "duplicate": false
    },
    {
      "type": "reply",
      "timestamp": null,
      "bytes": 64,
      "response_ip": "192.168.21.1",
      "icmp_seq": 4,
      "ttl": 64,
      "time_ms": 1.66,
      "duplicate": false
    }
  ]
}

PowerShell has something similar: INPUT/OUTPUT is more objects and less a byte stream as it is in Unix. Now I have both: byte stream by default, and JSON structured data if I want to! It’s like eating a cake and keeping it too!

Wireguard VPN

Tested between my home machine and my server-on-the-Internet, and…it just worked once I stopped using my usual Debian 10 server and “upgraded” to Ubuntu 20.04. Really good description is here.

Significantly easier to configure compared to SoftEther which is what I used before. SoftEther can do much more though, but if all you want is a VPN tunnel, Wireguard it is.

HTTPS on Synology’s DSM

My NAS is a Synology DS212 and it can do https. But to make it use my own CA’s certificate, a bit extra work is needed:

Add my own root CA’s Certificate

# Copy to the default folder for CA Root Certs of DSM 
cp root_ca.crt /usr/share/ca-certificates/mozilla/myCA.crt

# Linking to the system folder
ln -s /usr/share/ca-certificates/mozilla/myCA.crt /etc/ssl/certs/myCA.pem 

# Create hashed link
cd /etc/ssl/certs
ln -s myCA.pem `openssl x509 -hash -noout -in myCA.pem`.0

cat myCA.pem >> /etc/ssl/certs/ca-certificates.crt

# Testing
openssl verify -CApath /etc/ssl/certs myCA.pem

Use our own TLS Certificate

Create certificate

step ca certificate ds.lan ds.crt ds.key --kty RSA --size 2048 --not-after=8760h

DSM → Control Panel → Security → Certificate → Add. Then Configure and use the new one as system default.

Now https://ds.lan:5001 will use the new certificate. Repeat in 1 year. Since the default maximum lifetime of certificates was 720h, I had to change this to 1 year (8760h) on the step CA server:

    "minTLSCertDuration": "5m", 
    "maxTLSCertDuration": "8760h",
    "defaultTLSCertDuration": "24h",

CGroups V2 on Debian

CGroups V2 is not enabled by default on Debian, but it can be enabled easily:

# echo 'GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT} systemd.unified_cgroup_hierarchy=1"' >> /etc/default/grub
# grub-mkconfig -o /boot/grub/grub.cfg
# reboot

To find out which cgroups version you use, this is v1:

❯ ls /sys/fs/cgroup
 blkio  cpuacct      cpuset   freezer  memory   net_cls,net_prio  perf_event  rdma     unified
 cpu    cpu,cpuacct  devices  hugetlb  net_cls  net_prio          pids        systemd

and this is v2:

ls /sys/fs/cgroup 
cgroup.controllers  cgroup.max.descendants  cgroup.stat             cgroup.threads  system.slice 
cgroup.max.depth    cgroup.procs            cgroup.subtree_control  init.scope      user.slice

Hiding the Mouse Cursor in X

Konsole hides the mouse cursor when typing. This is generally good. But this is Konsole’s behavior and not a general one. I don’t generally want the mouse cursor when typing. So how to remove it?

Help comes from an old utility: xbanish. Clone the repo, and assuming you got the needed items to compile, 0.2s later you got a 27k binary. Refreshing.

❯ time make
cc -O2 -Wall -Wunused -Wmissing-prototypes -Wstrict-prototypes -Wunused -I/usr/X11R6/include -c xbanish.c -o xbanish.o
cc xbanish.o -L/usr/X11R6/lib -lX11 -lXfixes -lXi -o xbanish
make  0.18s user 0.04s system 84% cpu 0.265 total

❯ ls -la xbanish
-rwxr-xr-x 1 harald users 27288 Sep 22 09:05 xbanish

Put it in /usr/local/bin and make it autostart when KDE starts. And now the mouse cursor disappears in any X11 program.

k3s – local persistent storage

When using k3s and the built-in local persistent storage provider, once in a while you have to edit those files. While that usually works, sometimes you have to replace a 150kB binary file and when containers usually don’t have scp installed, there’s a problem…

The fix is to modify the storage from outside the container. That depends on the persistent storage provider. If it’s NFS, mount by NFS from another machine. If it’s an S3 bucket, edit it directly etc.

k3s has a local persistent storage driver called “local-path”. But where are those files so I can replace one of them? Turns out they are on /var/lib/rancher/k3s/storage/ on a node. Which node and what directory inside storage/ ?

Finding Your PVC

To find the PVC named “grafana-lib”, do

❯ kubectl describe persistentVolumeClaim grafana-lib
Name:          grafana-lib
Namespace:     default
StorageClass:  local-path
Status:        Bound
Volume:        pvc-a89cee51-0000-47d7-a095-2d48400768e3
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
               volume.beta.kubernetes.io/storage-provisioner: rancher.io/local-path
               volume.kubernetes.io/selected-node: knode5
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      3Gi
Access Modes:  RWO
VolumeMode:    Filesystem
Mounted By:    grafana-deployment-669fc6d658-l78z7
Events:        <none>

and the volume shows where it is: knode5:/var/lib/rancher/k3s/storage/pvc-a89cee51…
A bit of jq magic and you get a complete list of all PVCs:

❯ kubectl get persistentVolumeClaims -o json | jq '[.items[] | { "Name": .metadata.name, "Volume": .spec.volumeName, "Node": .metadata.annotations."volume.kubernetes.io/selected-node" }]'
[
  {
    "Name": "influxdb-data",
    "Volume": "pvc-bbac2312-0000-450e-aee1-41a0d5517adb",
    "Node": "knode6"
  },
  {
    "Name": "grafana-log",
    "Volume": "pvc-22814c7b-0000-4b8b-99b6-ab4a4ca6c65c",
    "Node": "knode5"
  },
  {
    "Name": "grafana-lib",
    "Volume": "pvc-a89cee51-0000-47d7-a095-2d48400768e3",
    "Node": "knode5"
  }
]

Disabling Waking up Computer via Mouse

My Linux machine keeps on waking up someone moves the mouse. Or kicks the table. While it’ll go back to sleep eventually, I’d rather not have it awake unless I want to use it.

Disabling mouse events to wake up your computer is surprisingly simple. The thing to know is /proc/acpi/wakeup:

❯ cat /proc/acpi/wakeup
Device  S-state   Status   Sysfs node
GPP0      S4    *disabled
GPP1      S4    *enabled   pci:0000:00:01.2
GPP2      S4    *disabled
GPP3      S4    *disabled
GPP4      S4    *enabled   pci:0000:00:01.5
GPP5      S4    *enabled   pci:0000:00:01.6
GPP6      S4    *disabled
GP17      S4    *enabled   pci:0000:00:08.1
XHC0      S3    *enabled   pci:0000:04:00.3
XHC1      S3    *enabled   pci:0000:04:00.4
GP18      S4    *enabled   pci:0000:00:08.2
SIO1      S3    *disabled  pnp:00:03

XHCx is the USB 3 controller which is where the mouse is connected to. Turn off via

echo "XHC0" >/proc/acpi/wakeup
echo "XHC1" >/proc/acpi/wakeup

and that’s it! To make it persistent put this into /etc/rc.local and make sure it runs during power-up.

Note

Running the echo command again will simply change between disabled and enabled.

Crosh and Web Fonts

Crosh, the Crostini shell, uses CSS to render the terminal. Gives you nice capabilities, but it’s also not compatible how normal Linux is configured.

Zsh and in particular the PowerLevel10k theme uses Unicode characters quite a bit.

So step 1 is using a font which works:

  1. Open the crosh terminal
  2. Control-Shift-P
  3. In the Text Font Family field, enter:
    “DejaVu Sans Mono”, monospace
  4. In the Custom CSS URI field, enter:
    https://cdn.rawgit.com/wernight/powerline-web-fonts/e4d967ca4f95d9fa0cf1d51afed2e5a5927d759e/PowerlineFonts.css

Instead of DejaVu Sans Mono, use another one in the list from the CSS file. Like Hack or Source Code Pro.