Adds Libvirt Handler
[pharos.git] / tools / laas-fog / source / domain.py
1 """
2 #############################################################################
3 #Copyright 2017 Parker Berberian and others                                 #
4 #                                                                           #
5 #Licensed under the Apache License, Version 2.0 (the "License");            #
6 #you may not use this file except in compliance with the License.           #
7 #You may obtain a copy of the License at                                    #
8 #                                                                           #
9 #    http://www.apache.org/licenses/LICENSE-2.0                             #
10 #                                                                           #
11 #Unless required by applicable law or agreed to in writing, software        #
12 #distributed under the License is distributed on an "AS IS" BASIS,          #
13 #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
14 #See the License for the specific language governing permissions and        #
15 #limitations under the License.                                             #
16 #############################################################################
17 """
18
19 import xml.dom
20 import xml.dom.minidom
21 import yaml
22
23
24 class Domain:
25     """
26     This class defines a libvirt vm abstraction that can parse our simple
27     config file and add all necessary boiler plate and info to write a full xml
28     definition of itself for libvirt.
29     """
30
31     def __init__(self, propertiesDict):
32         """
33         init function.
34         properiesDict should be one of the dictionaries returned by the static
35         method parseConfigFile
36         """
37         self.name = propertiesDict['name']
38         self.memory = propertiesDict['memory']
39         self.vcpus = propertiesDict['vcpus']
40         self.disk = propertiesDict['disk']
41         self.iso = propertiesDict['iso']
42         # the vm will either boot from an iso or pxe
43         self.netBoot = not self.iso['used']
44         self.interfaces = propertiesDict['interfaces']
45
46     def toXML(self):
47         """
48         combines the given configuration with a lot of
49         boiler plate to create a valid libvirt xml
50         definition of a domain.
51         returns a string
52         """
53         definition = xml.dom.minidom.parseString("<domain>\n</domain>")
54         definition.documentElement.setAttribute('type', 'kvm')
55
56         nameElem = definition.createElement('name')
57         nameElem.appendChild(definition.createTextNode(self.name))
58         definition.documentElement.appendChild(nameElem)
59
60         memElem = definition.createElement('memory')
61         memElem.appendChild(definition.createTextNode(str(self.memory)))
62         definition.documentElement.appendChild(memElem)
63
64         curMemElem = definition.createElement('currentMemory')
65         curMemElem.appendChild(definition.createTextNode(str(self.memory)))
66         definition.documentElement.appendChild(curMemElem)
67
68         vcpuElem = definition.createElement('vcpu')
69         vcpuElem.appendChild(definition.createTextNode(str(self.vcpus)))
70         definition.documentElement.appendChild(vcpuElem)
71
72         osElem = definition.createElement('os')
73
74         typeElem = definition.createElement('type')
75         typeElem.setAttribute('arch', 'x86_64')
76         typeElem.appendChild(definition.createTextNode('hvm'))
77         osElem.appendChild(typeElem)
78
79         if self.netBoot:
80             bootElem = definition.createElement('boot')
81             bootElem.setAttribute('dev', 'network')
82             osElem.appendChild(bootElem)
83
84         bootElem = definition.createElement('boot')
85         bootElem.setAttribute('dev', 'hd')
86         osElem.appendChild(bootElem)
87
88         if self.iso['used']:
89             bootElem = definition.createElement('boot')
90             bootElem.setAttribute('dev', 'cdrom')
91             osElem.appendChild(bootElem)
92
93         definition.documentElement.appendChild(osElem)
94
95         featureElem = definition.createElement('feature')
96         featureElem.appendChild(definition.createElement('acpi'))
97         featureElem.appendChild(definition.createElement('apic'))
98
99         definition.documentElement.appendChild(featureElem)
100
101         cpuElem = definition.createElement('cpu')
102         cpuElem.setAttribute('mode', 'custom')
103         cpuElem.setAttribute('match', 'exact')
104         modelElem = definition.createElement('model')
105         modelElem.appendChild(definition.createTextNode('Broadwell'))
106         cpuElem.appendChild(modelElem)
107
108         definition.documentElement.appendChild(cpuElem)
109
110         clockElem = definition.createElement('clock')
111         clockElem.setAttribute('offset', 'utc')
112
113         timeElem = definition.createElement('timer')
114         timeElem.setAttribute('name', 'rtc')
115         timeElem.setAttribute('tickpolicy', 'catchup')
116         clockElem.appendChild(timeElem)
117
118         timeElem = definition.createElement('timer')
119         timeElem.setAttribute('name', 'pit')
120         timeElem.setAttribute('tickpolicy', 'delay')
121         clockElem.appendChild(timeElem)
122
123         timeElem = definition.createElement('timer')
124         timeElem.setAttribute('name', 'hpet')
125         timeElem.setAttribute('present', 'no')
126         clockElem.appendChild(timeElem)
127
128         definition.documentElement.appendChild(clockElem)
129
130         poweroffElem = definition.createElement('on_poweroff')
131         poweroffElem.appendChild(definition.createTextNode('destroy'))
132
133         definition.documentElement.appendChild(poweroffElem)
134
135         rebootElem = definition.createElement('on_reboot')
136         rebootElem.appendChild(definition.createTextNode('restart'))
137
138         definition.documentElement.appendChild(rebootElem)
139
140         crashElem = definition.createElement('on_reboot')
141         crashElem.appendChild(definition.createTextNode('restart'))
142
143         definition.documentElement.appendChild(crashElem)
144
145         pmElem = definition.createElement('pm')
146         memElem = definition.createElement('suspend-to-mem')
147         memElem.setAttribute('enabled', 'no')
148         pmElem.appendChild(memElem)
149         diskElem = definition.createElement('suspend-to-disk')
150         diskElem.setAttribute('enabled', 'no')
151         pmElem.appendChild(diskElem)
152
153         definition.documentElement.appendChild(pmElem)
154
155         deviceElem = definition.createElement('devices')
156
157         emuElem = definition.createElement('emulator')
158         emuElem.appendChild(definition.createTextNode('/usr/libexec/qemu-kvm'))
159         deviceElem.appendChild(emuElem)
160
161         diskElem = definition.createElement('disk')
162         diskElem.setAttribute('type', 'file')
163         diskElem.setAttribute('device', 'disk')
164
165         driverElem = definition.createElement('driver')
166         driverElem.setAttribute('name', 'qemu')
167         driverElem.setAttribute('type', 'qcow2')
168         diskElem.appendChild(driverElem)
169
170         sourceElem = definition.createElement('source')
171         sourceElem.setAttribute('file', self.disk)
172         diskElem.appendChild(sourceElem)
173
174         targetElem = definition.createElement('target')
175         targetElem.setAttribute('dev', 'hda')
176         targetElem.setAttribute('bus', 'ide')
177         diskElem.appendChild(targetElem)
178
179         deviceElem.appendChild(diskElem)
180
181         if self.iso['used']:
182             diskElem = definition.createElement('disk')
183             diskElem.setAttribute('type', 'file')
184             diskElem.setAttribute('device', 'cdrom')
185
186             driverElem = definition.createElement('driver')
187             driverElem.setAttribute('name', 'qemu')
188             driverElem.setAttribute('type', 'raw')
189             diskElem.appendChild(driverElem)
190
191             sourceElem = definition.createElement('source')
192             sourceElem.setAttribute('file', self.iso['location'])
193             diskElem.appendChild(sourceElem)
194
195             targetElem = definition.createElement('target')
196             targetElem.setAttribute('dev', 'hdb')
197             targetElem.setAttribute('bus', 'ide')
198             diskElem.appendChild(targetElem)
199
200             diskElem.appendChild(definition.createElement('readonly'))
201             deviceElem.appendChild(diskElem)
202
203         for iface in self.interfaces:
204             ifaceElem = definition.createElement('interface')
205             ifaceElem.setAttribute('type', iface['type'])
206             sourceElem = definition.createElement('source')
207             sourceElem.setAttribute(iface['type'], iface['name'])
208             modelElem = definition.createElement('model')
209             modelElem.setAttribute('type', 'e1000')
210             ifaceElem.appendChild(sourceElem)
211             ifaceElem.appendChild(modelElem)
212             deviceElem.appendChild(ifaceElem)
213
214         graphicElem = definition.createElement('graphics')
215         graphicElem.setAttribute('type', 'vnc')
216         graphicElem.setAttribute('port', '-1')
217         deviceElem.appendChild(graphicElem)
218
219         consoleElem = definition.createElement('console')
220         consoleElem.setAttribute('type', 'pty')
221         deviceElem.appendChild(consoleElem)
222
223         definition.documentElement.appendChild(deviceElem)
224         return definition.toprettyxml()
225
226     def writeXML(self, filePath):
227         """
228         writes this domain's xml definition to the given file.
229         """
230         f = open(filePath, 'w')
231         f.write(self.toXML())
232         f.close()
233
234     @staticmethod
235     def parseConfigFile(path):
236         """
237         parses the domains config file
238         """
239         configFile = open(path, 'r')
240         try:
241             config = yaml.safe_load(configFile)
242         except Exception:
243             print "Invalid domain configuration. exiting"
244         return config