Search code examples
pythoncentossubprocesskvmlibvirt

Why am I getting inconsistencies running virt-install BASH script vs using Python's subprocess.run() function during boot with Anaconda?


I'm trying to convert my kvm build script written in BASH to Python. In BASH, I've written the following lines within my script to execute a fresh KVM instance built from an ISO image:

virt-install \
    --name=${VMNAME} \
    --ram=${MEMSIZE} \
    --vcpus=${VCPUS} \
    --os-type "linux" \
    --location ${ISOFILE} \
    --file=/var/lib/libvirt/images/${VMNAME}.dsk \
    --file-size=${DISKSIZE} \
    --network bridge=br0 \
    --graphics=none \
    --os-variant="rhel7" \
    -x 'console=ttyS0,115200n8 serial' \
    -x "ks=http://192.168.1.10/boot/centos7.ks"

This creates a successful build, and is visible through the "virsh" console using virt-install.

The script I'm using in Python to mimic what is happening in my BASH script looks like this:

kvm_cmd = ['/usr/bin/virt-install', \
           '--name=' + SELECT_SPECS[0], \
           '--ram=' + SELECT_SPECS[2], \
           '--vcpus=' + SELECT_SPECS[3], \
           '--os-type=linux', \
           '--location=' + CONFIG_VM[1], \
           '--file=/var/lib/libvirt/images/' + SELECT_SPECS[0] + '.dsk', \
           '--file-size=' + SELECT_SPECS[4], \
           '--network=bridge:br0', \
           '--nographics', \
           '--os-variant=' + CONFIG_VM[2], \
           '-x "console=ttyS0,115200n8 serial"', \
           '-x "ks=' + KS_REPO + CONFIG_VM[0] + '.ks"']
process = subprocess.run(kvm_cmd, stdout=subprocess.PIPE)
print(kvm_cmd)
print('VM ' + SELECT_SPECS[0] + ' created!')
return

Right now, I'm trying to perform the BASH command using Python's subprocess.run() function. Although I'm not seeing the serial output during run time, I can send a ^] signal while the Python script is running to exit out of the console, and re-enter the virsh console in another window/terminal.

Entering console, I can see that the installation runs into some anaconda issues that report "Kickstart file /run/install/ks.cfg is missing".

I can confirm that all my command argument variables are where they belong. I've used both --network bridge:br0 and --bridge=br0 for testing, as well as defining a kickstart file locally with '-x "ks=file:/centos7.ks' and --initrd-inject=/path/to/centos7.ks with the same results.

['/usr/bin/virt-install', '--name=test', '--ram=2048', '--vcpus=1', '--os-type=linux', \
 '--location=/DataStore/ISOs/CentOS-7-x86_64-Minimal-1708.iso', '--file=/var/lib/libvirt/images/test.dsk', \ 
 '--file-size=20', '--bridge=br0', '--graphics=none', '--os-variant=rhel7', '-x  \
 "console=ttyS0,115200n8 serial"', '-x "ks=http://192.168.1.10/boot/centos7.ks"']

Can anyone help me figure out why the kickstart won't load using python's Subprocess.run() function, but I can run it no problem when I run the command in BASH?

Is there a better way to create my kvm's with the details mentioned other than using BASH virt-install in a subprocess, preferably with a Python library? I've had a look at libvirt, but could not find a solution to my BASH query.


Solution

  • The equivalent to the shell script fragment:

        -x 'console=ttyS0,115200n8 serial' \
        -x "ks=http://${KS_REPO}/boot/${CONFIG_VM}.ks"
    

    is (assuming a new enough Python to support f-strings for brevity):

    [
        '-x', 'console=ttyS0,115200n8 serial',
        '-x', f'ks=http://{KS_REPO}/boot/{CONFIG_VM[0]}.ks',
    ]
    

    No literal quotes, only syntactic ones, in both languages.