Friday, October 4, 2019

Create virutal machine on KVM hypervisor using Libvirt API with Python and PXE with kickstart

Summary:


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()