Friday, March 18, 2022

how to shrink disk on qcow2 image (with an xfs filesystem)

abstract

This explains how to shrink (or change the size of the disk) of a qcow2 image.
qcow2 images are used in VMware virtual machines.
I am converting everything to vdi to test with virtualbox, so I can test directly in my computer.

Basically, you can't directly shrink a qcow2 image (using xfs). The actual process is to make another image (with a different disk size), copying all the existing contents from the original one.
For simplicity, this image is a GNU/Linux system (centos), with a grub2 bootloader.
I'm doing all these commands on a Debian 11 system.

steps overall

1. convert qcow2 to vdi
2. create new disk for new disk size, and another to locally save the backup (temp)
3. attach the new and the old image disks (vdi) to the VM
4. create new filesystems, mount and backup/restore the old image files
5. copy mbr to new system
6. update `/boot/grub2` and `/etc/fstab` for the new disk's uuid, and remove grub2 admin password (in case your original image had the grub2 admin password set)
7. convert vdi to qcow2

pre-requirements

1. the qcow2 image (can download from openstack)
2. virtualbox with a working GNU/Linux OS (to run from a live CD ISO image is OK too)

steps with commands in detail


# 1. convert qcow2 to vdi
# (get the image to your local machine first)
qemu-img convert -O vdi some_image.qcow2 some_image_backup.vdi

# 2. create new disk for new disk size, and another to locally save the backup (temp)
# use virtualbox's GUI for this
# create new_disk.vdi. And temp_disk.vdi if you are running a live CD. Using your local disk is OK too.

# 3. attach the new and the old image image disks (vdi) to the VM
# use virtualbox's GUI for this. It's done in the "storage" tab

# 4. create new filesystems, mount and backup/restore the old image files
cd /mnt
mkdir old_random_image
mkdir new_random_image
mkdir temp_disk

fdisk -l /dev/sda
n
ENTER bunch of times
w

# same for /dev/sdb
mkfs.ext4 /dev/sda1
mkfs.xfs /dev/sdb1

mount /dev/sda1 temp_disk
mount /dev/sdb1 new_random_image
mount /dev/sdc1 old_random_image
cd temp_disk

apt-get update
apt-get install xfsdump parted
xfsdump -f random_image.dump /mnt/old_random_image
# use random names for job and disk labels like: foo, foo2, bar, etc

xfsrestore -f random_image.dump /mnt/new_random_image

# use df -h and ls to confirm the filesystems seem to match

# add boot permission
# check old image
parted /dev/sdc
p
Ctrl-D

# add boot flag to partition
parted /dev/sdb
p
toggle 1
boot
p
Ctrl-D

# 5. copy mbr to new system

# backup old mbr 
dd if=/dev/sdc of=orig_mbr bs=512 count=1

# copy MBR to new disk (booting part only, without the partition table definition)
dd if=orig_mbr of=/dev/sdb bs=446 count=1

# 6. update `/boot/grub2` and `/etc/fstab` for the new disk's uuid, and remove grub2 admin password
cp -r /boot/grub2  /boot/grub2_bk
cd /boot/grub2
rm user.cfg grub.cfg.*.rpmsave

# check the new disk's uuid
ls -lh /dev/disk/by-uuid/

# replace the old uuid with the new one, and remove password requiring config
vi grub.cfg

################################################################################
# (here is a diff for above)

78,87d80
< ### BEGIN /etc/grub.d/01_users ###
< if [ -f ${prefix}/user.cfg ]; then
<   source ${prefix}/user.cfg
<   if [ -n "${GRUB2_PASSWORD}" ]; then
<     set superusers="root"
<     export superusers
<     password_pbkdf2 root ${GRUB2_PASSWORD}
<   fi
< fi
< ### END /etc/grub.d/01_users ###
90c83
< menuentry 'CentOS Linux' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-XXXX-OLD-DISK-UID' {
---
> menuentry 'CentOS Linux' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-XXXX-NEW-DISK-UID' {
98c91
< 	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1'  OLD-DISK-UID
---
> 	  search --no-floppy --fs-uuid --set=root --hint='hd0,msdos1' NEW-DISK-UID 
100c93
< 	  search --no-floppy --fs-uuid --set=root OLD-DISK-UID
---
> 	  search --no-floppy --fs-uuid --set=root NEW-DISK-UID
102c95
< 	linux16 /boot/vmlinuz-XXX.x86_64 root=UUID=OLD-DISK-UID ro console=tty0 crashkernel=auto console=ttyS0,115200 audit=1 LANG=en_US.UTF-8
---
> 	linux16 /boot/vmlinuz-XXX.x86_64 root=UUID=NEW-DISK-UID ro console=tty0 crashkernel=auto console=ttyS0,115200 audit=1 LANG=en_US.UTF-8
105c98
# ...
################################################################################

# do the same for fstab
vi /etc/fstab
# should look like this:
# UUID=XXXXXXXXXXXXXXXXXXX  /                       xfs     defaults        0 0
# (this has the new disk's UUID)

# restart VM unmounting all disks but the new image
# and check it boots OK (probably can't get a prompt due to network settings, but you should
# get no kernel error, or booting errors like "no disk/booter found" etc)

# 7. convert vdi to qcow2
qemu-img convert -f vdi -O qcow2 ~/virtualbox_vms/disks/random_image10G.vdi some_image_10G.qcow2

# 8. upload image to openstack
openstack image create --disk-format qcow2 --container-format bare  --file image/some_image_10G.qcow2 img-name-in-openstack

booting cisco iosxrv in virtualbox

abstract

Cisco has some virtual images of their iosxr system (iosxrv), which aren't very easy to use.
This is how I got iosxrv to work on virtualbox.
The trickiest parts were that the specs fixed/imported by image are pretty large, so you have to scale them down to make it work. And that virtualbox apparently can't find the interface to do ssh forwarding so you can actually connect to the device (is my GUI client buggy?... idk, but found it in the xml file you're not supposed to edit manually, but that works if you do anyway).


overall steps

1. import ova image

2. change image specs/configs

3. boot image 

4. (on X) create default user

5. (on X) setup ssh server and interface

6. confirm you can ssh with a localhost high port


Prerequisites

1. virtualbox

2. image files (ova files)

3. an X working system (connect from a GNU/Linux system on your client end, or install a windows client)

I did this on my debian server, on both a physical machine, and a VM, worked just fine.


steps


# ssh to the VM with the -X option, so you can run X programs from the server
ssh -X YOUR_SERVERS_IP_ADDR


# sample for 6.5.2. Please replace VM/image name as needed
# import image

VBoxManage import xrv9k-fullk9-x.vrr.vga-6.5.2.ova


# change name
VBoxManage modifyvm com.cisco.ios-xrv9000 --name iosxrv6.5.2


# change default options that make VM unbootable
VBoxManage modifyvm iosxrv6.5.2 --vtxux on
VBoxManage modifyvm iosxrv6.5.2 --ostype Linux_64
VBoxManage modifyvm iosxrv6.5.2 --cpus 6
VBoxManage modifyvm iosxrv6.5.2 --memory 7096
VBoxManage modifyvm iosxrv6.5.2 --vram 10
VBoxManage modifyvm iosxrv6.5.2 --longmode on
VBoxManage modifyvm iosxrv6.5.2 --graphicscontroller vmsvga


# add ssh port forwarding settings from virtualbox
VBoxManage modifyvm iosxrv6.5.2 --nic6 nat

# Change local port ("5801" here) and connection name (ssh_652) per VM.
# The rest stays the same
VBoxManage modifyvm iosxrv6.5.2 --natpf6 ssh_652,tcp,127.0.0.1,5801,10.0.7.15,22


# check mac address
grep "Adapter slot=\"5\"" ~/ ~/VirtualBox\ VMs/iosxr\ 6.5.2/*box # replace dir as necessary

#    <Adapter slot="5" enabled="true" MACAddress="XXXX" cable="true" type="XXXX">
# we'll use this to confirm on the VM side later that the right interface
# is being addressed

# boot once with X on
# it will be super slow (like 10m?), but it should boot. And ask you for your
# new root username/password

VBoxManage startvm iosxrv6.5.2


##################
# on the X window
##################

# create the new user following the prompt's instructions


# name the device, and setup the ssh server
conf t
hostname iosxr652
commit
exit

crypto key generate rsa
conf t
ssh server v2
line default transport input ssh
commit
exit

# setup interface for ssh forwarding
show int MgmtEth0/RP0/CPU0/0

# confirm mac address is the right one for our port forward
# you should get somewhere around the top a string representing the mac address
# check it matches the string got in the above step "check mac address"
# if not, to check which MAC address matches the mgmt interface, and do the NAT
# ssh port settings to that one instead

conf t
interface MgmtEth0/RP0/CPU0/0
 ipv4 address dhcp
 no shutdown
commit
exit
exit


# confirm interface is up and has an IP address assigned
show int MgmtEth0/RP0/CPU0/0

# we're assuming the IP address is 10.0.7.15
# if not, change NAT ssh forwarding settings accordingly

########################
# outside the X window
# (on your regular terminal)
########################

# (on the host running virtualbox)
ssh random_admin@localhost -p 5801 # replace username as necessary

# you should be able to login
# click the close button on the X window with the VM, and choose "shutdown VM"

# start VM again, with no X window
VBoxManage startvm --type headless iosxrv6.5.2

# after 10m or so, confirm you can ssh again
ssh random_admin@localhost -p 5801

# that's it!

# to stop:
# VBoxManage controlvm iosxrv6.5.2 poweroff