Define domain on KVM using Python with Libvirt API. This blog shows how to setup and manage a virtualized environment with KVM in CentOS 7 on GCP using python with libvirt api.
Environment:
- GCP environment
- Centos 7 with KVM hypervisor
- Centos 7 with PXE server + dnsmasq ( 192.168.122.99 )
- Python 2.6
- Libvirt API
Phase 1 - Install and configure DNSMASQ Server :
# yum install dnsmasq
# mv /etc/dnsmasq.conf /etc/dnsmasq.conf.backup
# vim /etc/dnsmasq.conf
interface=eth0,lo
#bind-interfaces
domain=centos7.lan
# DHCP range-leases
dhcp-range= eth0,192.168.122.201,192.168.122.253,255.255.255.0,1h
# PXE
dhcp-boot=pxelinux.0,pxeserver,192.168.122.99
# Gateway
dhcp-option=3,192.168.122.1
# DNS
dhcp-option=6, 8.8.8.8
server=8.8.4.4
# Broadcast Address
dhcp-option=28,192.168.122.255
# NTP Server
dhcp-option=42,0.0.0.0
pxe-prompt="Press F8 for menu.", 3
enable-tftp
tftp-root=/var/lib/tftpboot
Install SYSLINUX Bootloaders :
# yum install syslinux
Install TFTP-Server and Populate it with SYSLINUX Bootloaders :
# yum install tftp-server
# cp -r /usr/share/syslinux/* /var/lib/tftpboot
Setup PXE Server Configuration File :
# mkdir /var/lib/tftpboot/pxelinux.cfg
# vim /var/lib/tftpboot/pxelinux.cfg/default
default menu.c32
prompt 0
timeout 30
MENU TITLE Devopsbar PXE Menu
label 1
menu label ^1 - Install Centos 7 with Local ftp Repo
kernel /centos7/vmlinuz
APPEND initrd=/centos7/initrd.img inst.repo=ftp://192.168.122.99/pub ks=ftp://192.168.122.99/pub/anaconda-ks.cfg console=ttyS0,115200n8
label 2
menu label ^2 - Boot from local media
localboot 0x80 console=ttyS0,115200n8
Add CentOS 7 Boot Images to PXE Server :
Download the iso image:
# cd /tmp
# wget https://mirrors.edge.kernel.org/centos/7.6.1810/isos/x86_64/CentOS-7-x86_64-Minimal-1810.iso
# wget https://mirrors.edge.kernel.org/centos/7.6.1810/isos/x86_64/sha256sum.txt
# sha256sum -c sha256sum.txt
# mount -o loop /tmp/CentOS-7-x86_64-Minimal-1810.iso /mnt
# mkdir /var/lib/tftpboot/centos7
# cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/centos7
# cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/centos7
Create CentOS 7 Local Mirror Installation Source :
# yum install vsftpd
# cp -r /mnt/* /var/ftp/pub/
# chmod -R 755 /var/ftp/pub
Start and Enable Daemons System-Wide :
# systemctl start dnsmasq vsftpd
# systemctl enable dnsmasq vsftpd
Open Firewall and Test FTP Installation Source :
# firewall-cmd --add-service=ftp --permanent ## Port 21
# firewall-cmd --add-service=dns --permanent ## Port 53
# firewall-cmd --add-service=dhcp --permanent ## Port 67
# firewall-cmd --add-port=69/udp --permanent ## Port for TFTP
# firewall-cmd --add-port=4011/udp --permanent ## Port for ProxyDHCP
# firewall-cmd --reload ## Apply rules
Phase 2 - Using Libvirt API with Python create domain (virtual machine) in KVM
Create kickstart file :
# vim /var/ftp/pub/anaconda-ks.cfg
#------Kickstart file start -----#
#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use network installation
url --url="ftp://192.168.122.99/pub/"
# Use text mode install
text
# Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=vda
# Keyboard layouts
keyboard --vckeymap=us --xlayouts=''
# System language
lang en_US.UTF-8
# Network information
network --bootproto=dhcp --device=eth0 --onboot=off --ipv6=auto --no-activate
network --hostname=localhost.localdomain
# Root password
rootpw --iscrypted $1$a5eUl5NQ$AhPdoY7I2KIUUtujR4Kcp1
# System services
services --enabled="chronyd"
# Do not configure the X Window System
skipx
# System timezone
timezone Asia/Kolkata --isUtc
# System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda
autopart --type=lvm
# Partition clearing information
clearpart --all --initlabel --drives=vda
%packages
@core
chrony
kexec-tools
%end
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
#------Kickstart file end -----#
Create domain input xml file required for Libvirt API :
# vim /tmp/vm-input.xml
#------input xml file start -----#
<domain type='kvm'>
<name>test-vm1</name>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static'>1</vcpu>
<os>
<type>hvm</type>
<kernel>/var/lib/libvirt/images/vmlinuz</kernel>
<initrd>/var/lib/libvirt/images/initrd.img</initrd>
<cmdline>console=ttyS0,115200n8 ks=ftp://192.168.122.99/pub/anaconda-ks.cfg ip=192.168.122.100 netmask=255.255.255.0</cmdline>
<bootmenu enable="yes" />
</os>
<features>
<acpi/>
<apic/>
</features>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/var/lib/libvirt/images/test-vm.qcow2'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</disk>
<interface type='bridge'>
<source bridge='virbr0'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
</devices>
</domain>
#------input xml file end-----#
Note:- Stroage image disk should be created before define domain /var/lib/libvirt/images/test-vm.qcow2
Create domain using python :
# python
Python 2.7.5 (default, Aug 7 2019, 00:51:29)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import libvirt
>>> connection = libvirt.open("qemu:///system")
>>> f=open("/tmp/vm-input.xml")
>>> xml=f.read()
>>> connection.defineXML(xml)
<libvirt.virDomain object at 0x7fa196ba4d10>
>>> f.close()