Imagine that you need to install a service (a daemon) outside on a virtual machine as silently as possible while it’s turned off. This method lets you install all necessary files without involving the user in the process. If this article allows you to save valuable time, then we’ve achieved our goal.
We’ll share our experience so you can know how to solve a similar task.
External hidden installation of a service on a virtual machine is a convenient method that will allow you to
- install any service without user intervention;
- install the same service on multiple systems.
It may be useful for installing system security or maintenance-related services, such as for user data protection or transferring data to another system.
Typically, a user turns on a system, installs the necessary software, then turns off the system. But using the method described below, you can do the same thing for multiple users without turning their systems on.
The main advantage is that installation takes place when virtual machines aren’t in use, saving users’ time and not requiring them to take additional action. This method lets you install a service in a centralized manner and lets your users start working at the touch of a button, waiting only two minutes instead of the five to seven with manual installation.
This method can also be an important option when supporting individual user systems if the administrator doesn’t have the opportunity to log in to a user’s machine.
Let’s consider an implementation in a Linux environment. In our example, we have Ubuntu Desktop 16.04 with a standard installation on the ext4 file system as a virtual machine for the QEMU hardware emulation system.
- Ubuntu is a free distribution of the Linux operating system.
- QEMU is a free, open-source virtualization tool that’s used to emulate various architectures.
- ext4 (also called ext4fs) is the Fourth Extended File System. It’s a journaling file system running under the Linux operating system. Ext4 was built on the platform of its predecessor, ext3, which is used to be the default file system for many popular GNU/Linux distributions.
We don’t have any ways to directly interact with the virtual machine through the network or by other means. But since it’s a virtual machine, there’s a disk, which is a regular file that you can modify to add information about starting the service (daemon) and to add the executable file itself. You can mount the disk using standard QEMU tools and work with data on it. You could also parse an image file, but that may take more than a month.
In our example, we’ll use the libguestfs library because it has the necessary functionality to perform this task. The utilities in libguestfs use the Linux kernel code and QEMU. They allow you to access almost any type of file system:
- All known Linux file systems (ext2/3/4, XFS, btrfs, etc.)
- Any Windows file system (VFAT and NTFS)
- any macOS and BSD file system
It’s also possible to access LVM2 volumes, MBR and GPT disk partitions, raw disks, qcow2, VirtualBox VDI, VMWare VMDK, Hyper-V VHD/VHDX, files, local devices, CD and DVD ISOs, SD cards, and remote directories via FTP, HTTP, SSH, iSCSI, NBD, GlusterFS, Ceph, Sheepdog, and so on.
Libguestfs doesn’t require root privileges. In addition, it can access and change images of virtual disks as well as view and edit files inside virtual machines from the outside.
For a better understanding libguestfs implementation, let’s start with writing and analyzing the code that starts a simple service (daemon). A daemon is a service of a Unix or Unix-like operating system that runs in the background without direct communication with the user.
Let’s create a simple daemon that will start every five seconds to write a message to the log about the current time.
We also need the systemd service file to run the script when the system boots. Here’s an example of a configuration file:
Now that we have the daemon and config files, let’s run and test our prototype. Guestfish, which is included in the libguestfs-tools package, provides us with a handy utility with a command-line interpreter. We’ll outline a simple script that will install our service on a powered off virtual machine.
In the service log, you can see that the service has appeared in the system and the executable file is in the right place, /usr/bin/daemon, but it doesn’t work and is disabled.
Usually, these are the commands to install the daemon in the system:
But the system is disabled by daemon-reload, which we don’t need, which means that we only need to enable a simple-daemon.service. There are two ways to do this. The first is to enable systemctl, and the second is to see how this operation works and implement it using file operations. As it turns out, the enable operation simply creates a symbolic link, which means that now only one line should be added to the script.
This is what launching a command in guestfish looks like in our case:
After this, we run the script and check the result. Everything works perfectly. Just put the script in order, add some beauty, and here’s the result:
In the end, we need to write a program that will perform the actions described in the script. The final program might look like this:
After all these uncomplicated manipulations, we’ve installed the service (a daemon) in a way that’s completely imperceptible to the virtual machine user, although to do this we still needed access to the host. This method is quite versatile and is easier than creating many installation packages and maintaining them. This is just a simple introductory example of the large and powerful libguestfs library.
Virtualization-related tasks on various platforms are one of Apriorit’s specialties. While building virtualization software solutions, our team has accumulated a number of useful tips and recipes that we would be glad to share with you.