""" ############################################################################# #Copyright 2017 Parker Berberian and others # # # #Licensed under the Apache License, Version 2.0 (the "License"); # #you may not use this file except in compliance with the License. # #You may obtain a copy of the License at # # # # http://www.apache.org/licenses/LICENSE-2.0 # # # #Unless required by applicable law or agreed to in writing, software # #distributed under the License is distributed on an "AS IS" BASIS, # #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # #See the License for the specific language governing permissions and # #limitations under the License. # ############################################################################# """ import xml.dom import xml.dom.minidom import yaml class Domain: """ This class defines a libvirt vm abstraction that can parse our simple config file and add all necessary boiler plate and info to write a full xml definition of itself for libvirt. """ def __init__(self, propertiesDict): """ init function. properiesDict should be one of the dictionaries returned by the static method parseConfigFile """ self.name = propertiesDict['name'] self.memory = propertiesDict['memory'] self.vcpus = propertiesDict['vcpus'] self.disk = propertiesDict['disk'] self.iso = propertiesDict['iso'] # the vm will either boot from an iso or pxe self.netBoot = not self.iso['used'] self.interfaces = propertiesDict['interfaces'] def toXML(self): """ combines the given configuration with a lot of boiler plate to create a valid libvirt xml definition of a domain. returns a string """ definition = xml.dom.minidom.parseString("\n") definition.documentElement.setAttribute('type', 'kvm') nameElem = definition.createElement('name') nameElem.appendChild(definition.createTextNode(self.name)) definition.documentElement.appendChild(nameElem) memElem = definition.createElement('memory') memElem.appendChild(definition.createTextNode(str(self.memory))) definition.documentElement.appendChild(memElem) curMemElem = definition.createElement('currentMemory') curMemElem.appendChild(definition.createTextNode(str(self.memory))) definition.documentElement.appendChild(curMemElem) vcpuElem = definition.createElement('vcpu') vcpuElem.appendChild(definition.createTextNode(str(self.vcpus))) definition.documentElement.appendChild(vcpuElem) osElem = definition.createElement('os') typeElem = definition.createElement('type') typeElem.setAttribute('arch', 'x86_64') typeElem.appendChild(definition.createTextNode('hvm')) osElem.appendChild(typeElem) if self.netBoot: bootElem = definition.createElement('boot') bootElem.setAttribute('dev', 'network') osElem.appendChild(bootElem) bootElem = definition.createElement('boot') bootElem.setAttribute('dev', 'hd') osElem.appendChild(bootElem) if self.iso['used']: bootElem = definition.createElement('boot') bootElem.setAttribute('dev', 'cdrom') osElem.appendChild(bootElem) definition.documentElement.appendChild(osElem) featureElem = definition.createElement('feature') featureElem.appendChild(definition.createElement('acpi')) featureElem.appendChild(definition.createElement('apic')) definition.documentElement.appendChild(featureElem) cpuElem = definition.createElement('cpu') cpuElem.setAttribute('mode', 'custom') cpuElem.setAttribute('match', 'exact') modelElem = definition.createElement('model') modelElem.appendChild(definition.createTextNode('Broadwell')) cpuElem.appendChild(modelElem) definition.documentElement.appendChild(cpuElem) clockElem = definition.createElement('clock') clockElem.setAttribute('offset', 'utc') timeElem = definition.createElement('timer') timeElem.setAttribute('name', 'rtc') timeElem.setAttribute('tickpolicy', 'catchup') clockElem.appendChild(timeElem) timeElem = definition.createElement('timer') timeElem.setAttribute('name', 'pit') timeElem.setAttribute('tickpolicy', 'delay') clockElem.appendChild(timeElem) timeElem = definition.createElement('timer') timeElem.setAttribute('name', 'hpet') timeElem.setAttribute('present', 'no') clockElem.appendChild(timeElem) definition.documentElement.appendChild(clockElem) poweroffElem = definition.createElement('on_poweroff') poweroffElem.appendChild(definition.createTextNode('destroy')) definition.documentElement.appendChild(poweroffElem) rebootElem = definition.createElement('on_reboot') rebootElem.appendChild(definition.createTextNode('restart')) definition.documentElement.appendChild(rebootElem) crashElem = definition.createElement('on_reboot') crashElem.appendChild(definition.createTextNode('restart')) definition.documentElement.appendChild(crashElem) pmElem = definition.createElement('pm') memElem = definition.createElement('suspend-to-mem') memElem.setAttribute('enabled', 'no') pmElem.appendChild(memElem) diskElem = definition.createElement('suspend-to-disk') diskElem.setAttribute('enabled', 'no') pmElem.appendChild(diskElem) definition.documentElement.appendChild(pmElem) deviceElem = definition.createElement('devices') emuElem = definition.createElement('emulator') emuElem.appendChild(definition.createTextNode('/usr/libexec/qemu-kvm')) deviceElem.appendChild(emuElem) diskElem = definition.createElement('disk') diskElem.setAttribute('type', 'file') diskElem.setAttribute('device', 'disk') driverElem = definition.createElement('driver') driverElem.setAttribute('name', 'qemu') driverElem.setAttribute('type', 'qcow2') diskElem.appendChild(driverElem) sourceElem = definition.createElement('source') sourceElem.setAttribute('file', self.disk) diskElem.appendChild(sourceElem) targetElem = definition.createElement('target') targetElem.setAttribute('dev', 'hda') targetElem.setAttribute('bus', 'ide') diskElem.appendChild(targetElem) deviceElem.appendChild(diskElem) if self.iso['used']: diskElem = definition.createElement('disk') diskElem.setAttribute('type', 'file') diskElem.setAttribute('device', 'cdrom') driverElem = definition.createElement('driver') driverElem.setAttribute('name', 'qemu') driverElem.setAttribute('type', 'raw') diskElem.appendChild(driverElem) sourceElem = definition.createElement('source') sourceElem.setAttribute('file', self.iso['location']) diskElem.appendChild(sourceElem) targetElem = definition.createElement('target') targetElem.setAttribute('dev', 'hdb') targetElem.setAttribute('bus', 'ide') diskElem.appendChild(targetElem) diskElem.appendChild(definition.createElement('readonly')) deviceElem.appendChild(diskElem) for iface in self.interfaces: ifaceElem = definition.createElement('interface') ifaceElem.setAttribute('type', iface['type']) sourceElem = definition.createElement('source') sourceElem.setAttribute(iface['type'], iface['name']) modelElem = definition.createElement('model') modelElem.setAttribute('type', 'e1000') ifaceElem.appendChild(sourceElem) ifaceElem.appendChild(modelElem) deviceElem.appendChild(ifaceElem) graphicElem = definition.createElement('graphics') graphicElem.setAttribute('type', 'vnc') graphicElem.setAttribute('port', '-1') deviceElem.appendChild(graphicElem) consoleElem = definition.createElement('console') consoleElem.setAttribute('type', 'pty') deviceElem.appendChild(consoleElem) definition.documentElement.appendChild(deviceElem) return definition.toprettyxml() def writeXML(self, filePath): """ writes this domain's xml definition to the given file. """ f = open(filePath, 'w') f.write(self.toXML()) f.close() @staticmethod def parseConfigFile(path): """ parses the domains config file """ configFile = open(path, 'r') try: config = yaml.safe_load(configFile) except Exception: print "Invalid domain configuration. exiting" return config