Use virt-install to fully automate the install for Devuan Ceres with preseed, March 2020 edition

I have previously written about using virt-install to automate installing a new Devuan GNU+Linux virtual machine in libvirt/qemu.

This article is the March 2020 edition, that uses devuan_ascii_2.1_amd64_dvd-1.iso which is the latest Devuan Ascii iso available.

With this new iso, a number of changes have been made to the image itself, that will interfere with the default settings of virt-install. The branding of the ISO file was updated, so now isoinfo shows “Devuan” in the name and not Debian.

$ isoinfo -J -i devuan_ascii_2.1_amd64_dvd-1.iso -x /.disk/info
Devuan GNU/Linux 2.1 (ascii) amd64 DVD1 - 2019-12-21 07:24:54 UTC

Virt-manager uses this identifying info to find the initramfs/initrd and kernel (“vmlinuz,” “linux,” or similar) to boot. With the branding change, the Devuan disc changed the name of its initrd for some reason.
I wrote a patch for /usr/share/virt-manager/virtinst/ for package virt-install-1.5.0-7.el7.noarch.

--- /usr/share/virt-manager/virtinst/	2020-02-20 21:06:53.515076802 -0500
+++ /usr/share/virt-manager/virtinst/	2020-02-20 21:41:17.649056883 -0500
@@ -1279,6 +1279,33 @@
         logging.debug("Didn't find any known codename in the URL string")
         return self.os_variant
+class DevuanDistro(DebianDistro):
+    name = "Devuan"
+    urldistro = "devuan"
+    def _is_install_cd(self):
+        # For install CDs
+        if not self._check_info(".disk/info"):
+            return False
+        if self.arch == "x86_64":
+            kernel_initrd_pair = ("linux",
+                                  "initrd.gz")
+        elif self.arch == "i686":
+            kernel_initrd_pair = ("install.386/vmlinuz",
+                                  "install.386/initrd.gz")
+        elif self.arch == "aarch64":
+            kernel_initrd_pair = ("install.a64/vmlinuz",
+                                  "install.a64/initrd.gz")
+        elif self.arch == "ppc64le":
+            kernel_initrd_pair = ("install/vmlinux",
+                                  "install/initrd.gz")
+        elif self.arch == "s390x":
+            kernel_initrd_pair = ("boot/linux_vm", "boot/root.bin")
+        else:
+            kernel_initrd_pair = ("install/vmlinuz", "install/initrd.gz")
+        self._hvm_kernel_paths += [kernel_initrd_pair]
+        self._xen_kernel_paths += [kernel_initrd_pair]
+        return True
 class UbuntuDistro(DebianDistro):

It’s clear that we are defining a number of architectures and the kernel and initrd pairs. I copied and altered the DebianDistro class to use the relevant info. I only tested with the x86_64 arch, but it should be easy for you to read the iso file for your architecture and adjust the other pairs as needed.
No word is out on if the initrd and kernel filenames will be static now in Devuan, so I have not tried to submit a patch upstream, who have refactored now anyway.
And now, here is my one-liner for installing with the following, updated preseed file.

vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=debiantesting -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.1_amd64_dvd-1.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} interface=auto" --debug --network type=bridge,source=br0 --noautoconsole

I usually omit the –no-autoconsole so my prompt returns after the VM has installed and rebooted.

Preseed file

# File: /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
# Locations:
#    /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
# Author: bgstack15
# Startdate: 2019-06-25
# Title: Preseed for devuan vms for
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#    2019-06-25 fork from centos7-ks.cfg
#    2019-12-29 fix up repos and in-target conclusion stuff
#    2020-02-27 heavy rewrite to use ascii 2.1
# Usage with virt-install:
#    vm=d2-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=debiantesting -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/devuan_ascii_2.1_amd64_dvd-1.iso --initrd-inject=/mnt/public/Support/Platforms/devuan/preseed/preseed.cfg --extra-args "hostname=${vm} interface=auto" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=d2-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt
#    syntax for --location
#    example preseed
#    skip next dvd question
#    grub problem caused by consolekit:amd64
#    /mnt/public/Support/Platforms/devuan/fix-virt-manager.txt
#    sudo debconf-get-selections -c /mnt/public/Support/Platforms/devuan/preseed/preseed.cfg
#    on d2-03a: sudo debconf-get-selections --installer
# Improve:
#    discover how to send email, using postfix or sendmail. Don't care which, but exclude exim4.
#    echo "$( hostname ) has IP $( ip -4 -o a s eth0 | awk '{print $4}' | sed -r -e 's/\/.*$//' )" | 
#    2020-02-24 add the kernel lines: console=ttyS0 console=tty1. Get this to work; use grub.cfg and "linux" line, not "kernel"

d-i debian-installer/country string US
d-i debian-installer/keymap select us
d-i debian-installer/language string en
d-i debian-installer/locale string en_US
d-i localechooser/supported-locales string en_US.UTF-8

d-i keyboard-configuration/layoutcode string us
d-i keyboard-configuration/variantcode string
d-i keyboard-configuration/xkb-keymap select us

d-i netcfg/disable_autoconfig boolean false
d-i netcfg/get_domain string
d-i netcfg/wireless_wep string
# disable asking for non-free firmware, because this is a vm and has none
d-i hw-detect/load_firmware boolean false

#d-i apt-setup/enable-source-repositories boolean false
# ORIGINAL d-i apt-setup/services-select multiselect security updates, release updates, backported software
d-i apt-setup/contrib boolean true
d-i apt-setup/disable-cdrom-entries boolean true
d-i apt-setup/non-free boolean true
d-i apt-setup/use_mirror boolean true
d-i mirror/country string manual
d-i mirror/http/directory string /merged
d-i mirror/http/hostname string
d-i mirror/http/proxy string
d-i mirror/protocol string http
d-i mirror/suite string testing

d-i apt-setup/cdrom/set-failed boolean false
d-i apt-setup/cdrom/set-first boolean false
d-i apt-setup/cdrom/set-next boolean false

## my repos and ceres
d-i apt-setup/local0/comment    string stack123deb
d-i apt-setup/local0/key        string
d-i apt-setup/local0/repository string /
d-i apt-setup/local1/comment    string devuan-deb
d-i apt-setup/local1/key        string
d-i apt-setup/local1/repository string /
d-i apt-setup/local2/comment    string ceres
d-i apt-setup/local2/key        string
d-i apt-setup/local2/repository string ceres main contrib non-free
#d-i apt-setup/local2/key        string
#d-i apt-setup/local2/repository string ceres main contrib non-free
d-i apt-setup/local3/comment    string obsmirror
d-i apt-setup/local3/key        string
d-i apt-setup/local3/repository string /
# if for some reason I really need to turn off the gpg key check:
#d-i debian-installer/allow_unauthenticated boolean false

#tasksel tasksel/first multiselect standard, ssh-server
tasksel tasksel/first multiselect none

# adapted from /mnt/public/Support/Platforms/devuan/devuan.txt, main fluxbox desktop, but for a vm
# no xscreensaver, for a vm.
#d-i pkgsel/include string \
#   alsamixergui alttab apt-transport-https bgconf bgscripts bgscripts-core \
d-i pkgsel/include string openssh-server

d-i pkgsel/upgrade select none

popularity-contest popularity-contest/participate boolean true

d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string
d-i time/zone string America/New_York

# skip grub during main part, because we will do it in late_command
#d-i grub-installer/skip boolean true
#d-i grub-installer/skip-again boolean true
#d-i grub-installer/skip-confirm boolean true
#d-i grub-installer/confirm_skip boolean true
#d-i nobootloader/confirmation_common boolean true
d-i     choose-init/select_init select  sysvinit
d-i     choose-init/selected_sysvinit bool   true
grub-installer  grub-installer/choose_bootdev   select  /dev/vda

d-i lilo-installer/skip boolean true
#d-i grub-installer/with_other_os boolean true
d-i grub-installer/only_debian boolean true
d-i grub-installer/grub2_instead_of_grub_legacy boolean true
#d-i grub-installer/bootdev string /dev/vda
#d-i grub-installer/choose_bootdev select /dev/vda
#grub-installer grub-installer/force-efi-extra-removable boolean false

d-i passwd/root-password password somethingStrongHere
d-i passwd/root-password-again password somethingStrongHere

d-i partman-auto/choose_recipe select home
d-i partman-auto-crypto/erase_disks boolean false
d-i partman-auto/disk string /dev/vda
d-i partman-auto/init_automatically_partition select biggest_free
d-i partman-auto/method string lvm
d-i partman/choose_label string gpt
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman/confirm_write_new_label boolean true
d-i partman/default_label string gpt
#d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-md/confirm_nooverwrite boolean true
#d-i partman/mount_style select uuid
d-i partman-partitioning/confirm_write_new_label boolean true

# Uncomment this to add multiarch configuration for i386
#d-i apt-setup/multiarch string i386

d-i passwd/make-user boolean true
d-i passwd/user-fullname string bgstack15-local
d-i passwd/username string bgstack15-local
d-i passwd/user-password-crypted password $6$85aKM2DkiD5g9r3D$zkBcVES1Bzu.b5dBJxklSGgEJzswZBlVAyc9lUUIzMA2OLRH3PD2ZWE9Q40ztw/32OyDm2nF031hfE4s5LGuG1
d-i passwd/user-default-groups string audio cdrom video

d-i finish-install/reboot_in_progress note
d-i cdrom-detect/eject boolean true

# additional application stuff just in case it works and is useful
# LDAP server URI:
d-i shared/ldapns/ldap-server	string	ldapi:///

d-i openssh-server/password-authentication	boolean	true
d-i openssh-server/permit-root-login	boolean	false

d-i preseed/late_command string mkdir -p /target/etc/apt/sources.list.d /target/mnt/bgstack15 /target/mnt/public ; cd /target/etc/apt ; \
   in-target wget -O /Release.gpg ; in-target apt-key add /Release.gpg ; \
   echo "deb ceres main contrib non-free" > sources.list ; \
   in-target wget -O /stack123deb.gpg ; in-target apt-key add /stack123deb.gpg ; \
   echo "deb /" > sources.list.d/stack123deb.list ; \
   echo "deb /" > sources.list.d/devuan-deb.list ; \
   in-target wget -O /Release.key ; in-target apt-key add /Release.key ; \
   echo "deb /" > sources.list.d/home\:bgstack15.list ; \
   in-target apt-get update ; \
   in-target apt-get purge -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" consolekit exim4\* lxqt\* udev ; \
   in-target apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" alsamixergui alttab apt-transport-https bgconf bgscripts bgscripts-core cifs-utils curl fluxbox freeipa-client git grub lightdm lightdm-gtk-greeter mlocate net-tools nfs-common ntpdate oddjob-mkhomedir=0.0.1-1 openssh-server p7zip palemoon-ublock-origin parted qemu-guest-agent rsync scite screen spice-vdagent strace sudo tcpdump vim vlc volumeicon-alsa xfce4-terminal xfe xserver-xorg-video-qxl fluxbox-themes-stackrpms xdgmenumaker man logout-manager freeipa-helper palemoon waterfox ; \
   in-target wget -O /usr/local/share/ca-certificates/ && update-ca-certificates || : ; \
   in-target su bgstack15-local -c "sudo /usr/bin/ -d 10 1>/home/bgstack15-local/clone.log 2>&1" ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target wget -O /root/ ; in-target sh /root/ ; \
   in-target apt-get install -q -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" postfix ; \
   in-target wget -O /root/ ; in-target sh /root/ preseed ; \
   in-target sed -i -r -e '/^\s*linux/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/grub.cfg | grep -E '^\s*linux' ; \
   in-target sed -i -r -e '/^\s*kernel/s/(\s*console=.{1,7}[0-9])*\s*$/ console=tty0 console=ttyS0/;' /boot/grub/menu.lst ; \
   in-target sed -i -r -e '$aT0:23:respawn:/sbin/getty -L ttyS0 9600 vt100' /etc/inittab ;

#   in-target install -m0644 /mnt/public/Support/Platforms/devuan/sources.list /etc/apt/sources.list ; \

For some reason, the pkgsel/include answer would not work here. Also, the native answers for custom apt repositories wouldn’t work, but it might have been implementation errors on my side. So I learned the tricky in-target or not in-target logic required to manipulate apt and install my phone book of packages.



My original conversation: Installing Devuan Ascii 2.1 with virt-install / Installation / Dev1 Galaxy Forum

Run spice-vdagent with X11

On Devuan beowulf/ceres, for some reason spice-vdagent is not started when X11 is started. I found what appears to be a proper way to do it: write file /etc/X11/Xsession.d/60spice-vdagent.

# -*- sh -*-
# Xsession.d script to start spice-vdagent
# This file is sourced by Xsession(5), not executed.

__AGENT="$( which spice-vdagent 2>/dev/null )"
test -x "${__AGENT}" && "${__AGENT}" &

Maybe this should be included in the spice-vdagent package…

Access vm in libvirt/qemu/kvm on serial console from hypervisor

You can access the serial port console of a virtual machine running in qemu, if you have configured the guest kernel correctly.

Configure the guest

# add serial console
sed -i -r -e '/^GRUB_CMDLINE_LINUX=/{s/(\s*)\"$/ console=ttyS0 console=tty1\"/;}' /etc/default/grub
grub2-mkconfig > /boot/grub2/grub.cfg

I have these steps in my kickstart %post scriptlet, so all my VMs get this setting. These steps modify grub to tell the kernel to open a listening console on the first serial console (ttyS0) and also the regular virtual terminal tty1. It is important to denote both, so the spice client sees the tty1, and that virsh on the command line can get to the serial console.

Accessing the guest from the hypervisor

sudo virsh console $GUESTNAME

Once the guest OS has booted, just run this command and you’re connected to the serial console. You have to log in like a true console session, and then you’re in!

A Devuan guest in kvm and using spice-vdagentd

If you intend to use spice-vdagent in a devuan vm, you might be interested to know how to get the spice agent to actually work.


The option for “Scale Display -> Auto resize VM with window” is not functional in the spice viewer.
In the guest’s /var/log/syslog, you can see an error:

spice-vdagentd: error getting session for pid 2970: no such file or directory free

But that’s about it.

The fix

Make file /etc/default/spice-vdagentd with contents:


Then restart the daemon.

sudo service spice-vdagentd restart

The -X flag on the invocation disables systemd-logind integration. This is key for a devuan install because devuan exists to be free of the requirement for systemd.


Internet searches



  1. 14.04 – Systemd, cgroup, and LXC – Ask Ubuntu
  2. Bug #1633609 “spice-vdagentd does not work” : Bugs : spice-vdagent package : Ubuntu
  3. Configuration for spice-vdagentd – Ask Ubuntu

Multiple monitors on Windows guest in KVM


It is easy to set up a virtual machine with the virt-manager GUI.

To add a second monitor (or more) is also pretty easy, once you know how to do it. However, to view a second monitor simultaneously with the first, you will need to use the tool remote-viewer.

In virt-manager, select “Show virtual hardware details.”
Screenshot of virt-manager open to a virtual machine, "Show virtual hardware details" page.
Add a new video card. A basic QXL type should be sufficient.

It is possible to connect to the guest’s displays over the network, if you configure it to be possible. For example, you use your desktop Virtual Machine Manager to connect to a server’s libvirt via a connection string like qemu+ssh://

On that virtual machine’s “Display spice” virtual hardware, modify the address tag to “All interfaces.” Also note the the port number given to this guest. In my screenshot you can see mine is port 5907.
Screenshot showing vm settings for display spice

You will want to open up the firewall on the vm host. I suggest just using the vdsm definition, which is for the oVirt project and includes TCP ports 5900-6923.

sudo firewall-cmd --permanent --add-service=vdsm; sudo firewall-cmd --reload

You will need to shut down (not reboot) the guest if it is running at the time, for it to be able to use the new virtual hardware or pretty much any new setting.

Once the virtual machine is running again, use “Remote Viewer” in the GUI, or run from the command line.

remote-viewer spice://


Learn how to do this in the cli, including maybe at the virt-install statement. Or at least how to retro-fit an existing domain.


  1. search “kvm spice guest windows multiple monitors”
  2. Shamelessly ripped off from
  3. spice guest tools

Linux get vmware tools version

$( { find /sbin /usr/sbin /usr/local/bin /bin /usr/bin -name 'vmtoolsd'; echo /bin/true; } | head -n1 ) -v

Regardless of deployment method (RHEL6 by inserting the virtual disc, or RHEL7 rpm for open-vm-tools), this should work for you.

Update on 2019-08-20

And from PowerCLI:

get-vm | % { get-view $ } | select Name, @{ Name="ToolsVersion"; Expression={$}},@{ Name="ToolStatus"; Expression={$_.Guest.ToolsVersionStatus}}


  1. Original research
  2. Powercli – How to get Vmware tools version – Virtual Me

Create, attach, detach disk to vm in kvm on command line

In kvm, let’s say you want to create a new disk and attach it to a virtual machine. You could use Virtual Machine Manager. But for the command line, here is a quick way how to do it.

Create a disk

Create a qcow2 disk that is fully allocated. When I tried with disks that were not fully allocated, the vm would only see the 200K or so and would not let me write a partition table large enough to do anything.

time qemu-img create -f qcow2 /var/lib/libvirt/images/vmname-vdb.qcow2 22000M -o preallocation=full

Attach a disk

You can omit the flags as needed, if you don’t want to update the virtual machine’s definition, or –config. And some of these are probably redundant, but they did not throw errors for me and I wanted the change to be immediate and persistent upon vm reboot, so I leave them all in.

virsh attach-disk --domain vmname /var/lib/libvirt/images/vmname-vdb.qcow2 --target vdb --persistent --config --live

Detach a disk

Same thing as the attaching, only you don’t include the –target flag.

virsh detach-disk --domain vmname /var/lib/libvirt/images/vmname-vdb.qcow2 --persistent --config --live



Man pages

  1. qemu-img

Fix Korora xfce spice display pausing

For the Fedora spin Korora with the xfce desktop running in a kvm virtual machine, the display might pause for 2 seconds every so often. The system is running, but sometimes the display just freezes.

To fix this issue, run the xfce “Window Manager Tweaks.” On the “Compositor tab” uncheck “Synchronize drawing to the vertical blank.”

Thanks to Jim at the Korora Project for this one!

Mount an lvm logical volume from a qcow2 file

Mounting qcow2 files to host filesystem

Converting to raw and mounting

kpartx does not work very well with qcow2 files. You can convert the qcow2 file to a raw file:

qemu-img convert "${oldfile}" "${newfile}"

You can now find the partitions and map them:

kpartx -av "${newfile}"
mount /dev/loop2p2 /mnt/foo

Modifying a virtual machine to use the new image file

You can modify a virtual machine definition to use this new file:

virsh dumpxml ${domain} > domain.xml
vi domain.xml # Lines “source file=/path/file.raw” and “driver name=qemu type=raw"
virsh create domain.xml

Mounting lvm logical volumes from the image file

Update lvm with the currently attached disks.

pvscan; lvscan; lvdisplay

Now you can mount /dev/mapper/cl_centos7–02a_root to a mount point.



  1. Converting qcow2 file to raw to make it work with kpartx
  2. An alternate way to mount a qcow2 file

Man pages

  1. virsh