-
Notifications
You must be signed in to change notification settings - Fork 6
/
forceVMstart.py
510 lines (416 loc) · 17 KB
/
forceVMstart.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
#!/usr/bin/env python
#
# Copyright 2010
#
# Licensed to you under the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Require Packages: python-iniparse
#
# Original script by:
# - Douglas Landgraf ([email protected])
# - Vladik Romanovsky ([email protected])
#
# Contributors:
# - Pablo Iranzo Gomez ([email protected])
###############################################################################
############## WARNING ##############
############## The use of this script is inherently raceful ##############
############## use it only on emergency cases when it's no ##############
############## possible to wait until manager is up again ##############
###############################################################################
import getopt
import sys
import commands
import os
import socket
from xml.dom.minidom import parse, parseString
try:
from iniparse import ConfigParser
except:
print "Package python-iniparse is required, please install"
print "#yum install python-iniparse -y"
sys.exit(1)
try:
from vdsm import vdscli
except:
print "Cannot import vdscli, please fix it"
sys.exit(1)
try:
import vdsClient
except:
print "Cannot import vdsClient, please fix it"
sys.exit(1)
# General Macros
VERSION = "1.0.0"
#DEBUG MODE
DEBUG = "False" # True or False
#########################################################################
class vdsmEmergency:
def __init__(self):
"""Initialize method"""
sslRet = self.checkSSLvdsm()
self.useSSL = sslRet
self.truststore = None
def do_connect(self, server, port):
"""Do a connection with vdsm daemon"""
print "Trying to connect to vdsmd host (%s).." % server
# Connection Validation
sk = socket.socket()
try:
sk.connect((server, int(VDSM_PORT)))
except Exception, e:
print "Unable to connect %s" % server
sk.close()
return -1
self.conn_info = vdscli.connect(server + ':' + port, self.useSSL,
self.truststore)
print "OK, Connected to vdsmd!"
return 0
def checkRoot(self):
"""check if the user running the script is root"""
if os.geteuid() != 0:
print "You must be root to run this script."
sys.exit(2)
def getIpManagementIP(self):
"""get the IP from management interface"""
# TODO: avoid this kind of hack, find a better approach (vdsClient
# provide the IP of ovirtmgmt/rhevm interface?)
#
# Code to make it work for the rhevm or the ovirtmgmt interface
strCmd = ("ifconfig ovirtmgmt 2>/dev/null|grep inet|grep -v inet6|" +
"awk '{print $2}'|cut -d ':' -f2")
retCmd = commands.getstatusoutput(strCmd)
if retCmd[1] == "":
strCmd = ("ifconfig rhevm 2>/dev/null|grep inet|grep -v inet6|" +
"awk '{print $2}'|cut -d ':' -f2")
retCmd = commands.getstatusoutput(strCmd)
if retCmd[0] != 0:
print "Error getting IP from management interface"
sys.exit(1)
return retCmd[1]
def checkSSLvdsm(self):
"""check if vdsm is running as SSL or without it"""
cfg = ConfigParser()
cfg.read('/etc/vdsm/vdsm.conf')
cfg.get('vars', 'ssl')
return cfg.data.vars.ssl
def checkVmRunning(self, otherHostsList, VmsToStart):
"""check if the vm's are running"""
hosts = None
vms = None
i = 0
j = 0
if otherHostsList is None:
return -1
if VmsToStart is None:
return -1
vms = VmsToStart.split(",")
hosts = otherHostsList.split(",")
# Let's check if all other Hosts are running the VirtualMachine
while (i != len(hosts)):
ret = VE.do_connect(hosts[i], VDSM_PORT)
if ret < 0:
sys.exit(1)
response = self.s.list()
if response['status']['code'] != 0:
print ("cannot execute list operation, err:" +
response['status']['message'])
# Checking VM status
for s in self.s.getAllVmStats()['statsList']:
j = 0
# print all vms in each host
while j < len(vms):
if DEBUG == "True":
print len(vms)
print s['vmId']
print hosts[i]
print vms[j]
vmIdCurr = self.getVmId(vms[j])
if DEBUG == "True":
print vmIdCurr
print s['vmId']
if s['vmId'] == vmIdCurr and s['status'] == "Up":
print ("Cannot continue, the VM %s is running" +
" in host %s" % (vms[j], hosts[i]))
sys.exit(1)
j = j + 1
# counter for hosts
i = i + 1
print ("OK, the vm(s) specified are not running on the host(s)" +
" informed, continuing..")
def checkSPM(self):
"""check if the host which is running this script is the SPM"""
self.spUUID = None
self.spmStatus = None
ip_management_interface = self.getIpManagementIP()
self.do_connect(ip_management_interface, VDSM_PORT)
try:
list = self.s.getConnectedStoragePoolsList()
except:
print "Cannot execute getConnectedStoragePoolsList()"
sys.exit(1)
# Shu Ming comments that this may not make any sense as it seems to
# be always the last entry FIXME
for entry in list['poollist']:
self.spUUID = entry
if not self.spUUID:
print "Cannot locate Storage Pools List.. aborting!"
sys.exit(1)
try:
status = self.s.getSpmStatus(self.spUUID)
except:
print "Cannot execute getSpmStatus()"
sys.exit(1)
self.spmStatus = status['spm_st']['spmStatus']
if self.spmStatus != "SPM":
print ("This host is not the current SPM, " +
"status [%s]" % self.spmStatus)
sys.exit(1)
def getVmId(self, vmName):
"""get the vmId from the vmName used as argument"""
path = "/rhev/data-center/%s/mastersd/master/vms" % (self.spUUID)
# First verify which domainID contain de XML files
try:
dirList = os.listdir(path)
except:
print "Cannot locate the dir with ovf files.. aborting!"
sys.exit(1)
#Read all content of xml(s) file(s)
for fname in dirList:
pathOVF = path + "/" + fname + "/" + fname + ".ovf"
dom = parse(pathOVF)
# Getting vmId field
i = 0
attr = 0
for node in dom.getElementsByTagName('Section'):
while (i < len(node.attributes)):
attr = node.attributes.items()
if attr[i][0] == "ovf:id":
vmId = attr[i][1]
i = i + 1
# Getting vmName field
for node in dom.getElementsByTagName('Content'):
if node.childNodes[0].firstChild is not None:
if node.childNodes[0].firstChild.nodeValue == vmName:
return vmId
def _parseDriveSpec(self, spec):
if ',' in spec:
d = {}
for s in spec.split(','):
k, v = s.split(':', 1)
if k == 'domain':
d['domainID'] = v
if k == 'pool':
d['poolID'] = v
if k == 'image':
d['imageID'] = v
if k == 'volume':
d['volumeID'] = v
if k == 'boot':
d['boot'] = v
if k == 'format':
d['format'] = v
return d
return spec
def readXML(self, VmsStotart, destHostStart):
"""read all xml available pointed to Directory path and parse for
specific fields"""
# number of Vms found
nrmVms = 0
cmd = {}
# Path to XML files
# example default path:
# /rhev/data-center/1a516f64-f091-4785-9278-362037513408/vms
path = "/rhev/data-center/%s/mastersd/master/vms" % (self.spUUID)
# First verify which domainID contain de XML files
try:
dirList = os.listdir(path)
except:
print "Cannot locate the dir with ovf files.. aborting!"
sys.exit(1)
# FIXME: The following loop code is iterating over files as well as
# starting VM's, this should be converted to a function
#Read all content of xml(s) file(s)
for fname in dirList:
pathOVF = path + "/" + fname + "/" + fname + ".ovf"
cmd['display'] = "vnc"
cmd['kvmEnable'] = "True"
cmd['tabletEnable'] = "True"
cmd['vmEnable'] = "True"
cmd['irqChip'] = "True"
cmd['nice'] = 0
cmd['keyboardLayout'] = "en-us"
cmd['acpiEnable'] = "True"
cmd['tdf'] = "True"
dom = parse(pathOVF)
# Getting vmId field
i = 0
attr = 0
for node in dom.getElementsByTagName('Section'):
while (i < len(node.attributes)):
attr = node.attributes.items()
if attr[i][0] == "ovf:id":
cmd["vmId"] = attr[i][1]
i = i + 1
# Getting vmName field
for node in dom.getElementsByTagName('Content'):
if node.childNodes[0].firstChild is not None:
self.vmName = node.childNodes[0].firstChild.nodeValue
cmd['vmName'] = self.vmName
# Getting image and volume
i = 0
attr = 0
for node in dom.getElementsByTagName('Disk'):
while (i != len(node.attributes)):
attr = node.attributes.items()
if attr[i][0] == "ovf:fileRef":
storage = attr[i][1]
data = storage.split("/")
image = data[0]
volume = data[1]
i += 1
# Getting VM format, boot
i = 0
attr = 0
for node in dom.getElementsByTagName('Disk'):
while (i != len(node.attributes)):
attr = node.attributes.items()
if attr[i][0] == "ovf:volume-format":
format = attr[i][1]
if attr[i][0] == "ovf:boot":
vmBoot = attr[i][1]
if attr[i][0] == "ovf:disk-interface":
ifFormat = attr[i][1]
i += 1
if format == "COW":
vmFormat = ":cow"
elif format == "RAW":
vmFormat = ":raw"
if ifFormat == "VirtIO":
ifDisk = "virtio"
elif ifFormat == "IDE":
ifDisk = "ide"
drives = []
# Getting Drive, bridge, memSize, macAddr, smp, smpCoresPerSocket
for node in dom.getElementsByTagName('Item'):
# Getting Drive
if node.childNodes[0].firstChild is not None:
str = node.childNodes[0].firstChild.nodeValue
if str.find("Drive") > -1:
tmp = ("pool:" + self.spUUID + ",domain:" +
node.childNodes[7].firstChild.nodeValue +
",image:" + image + ",volume:" + volume +
",boot:" + vmBoot + ",format" + vmFormat +
",if:" + ifDisk)
#param,value = tmp.split("=",1)
drives += [self._parseDriveSpec(tmp)]
cmd['drives'] = drives
# Getting bridge
nicMod = None
if node.childNodes[0].firstChild.nodeValue == ("Ethernet" +
"adapter on" +
" rhevm"):
if node.childNodes[3].firstChild.nodeValue == "3":
nicMod = "pv" # VirtIO
elif node.childNodes[3].firstChild.nodeValue == "2":
nicMod = "e1000" # e1000
elif node.childNodes[3].firstChild.nodeValue == "1":
nicMod = "rtl8139" # rtl8139
cmd['nicModel'] = nicMod
cmd['bridge'] = node.childNodes[4].firstChild.nodeValue
# Getting memSize field
str = node.childNodes[0].firstChild.nodeValue
if str.find("MB of memory") > -1:
cmd['memSize'] = node.childNodes[5].firstChild.nodeValue
# Getting smp and smpCoresPerSocket fields
str = node.childNodes[0].firstChild.nodeValue
if str.find("virtual cpu") > -1:
cmd["smp="] = node.childNodes[4].firstChild.nodeValue
cmd["smpCoresPerSocket"] = (
node.childNodes[5].firstChild.nodeValue)
# Getting macAddr field
if node.childNodes[0].firstChild.nodeValue == ("Ethernet" +
" adapter on" +
" rhevm"):
if len(node.childNodes) > 6:
cmd['macAddr'] = (
node.childNodes[6].firstChild.nodeValue)
# if node.childNodes < 6 it`s a template entry, so ignore
if len(node.childNodes) > 6:
# print only vms to start
try:
checkvms = VmsToStart.split(",")
except:
print "Please use , between vms name, avoid space"
self.usage()
i = 0
while (i != len(checkvms)):
if self.vmName == checkvms[i]:
nrmVms = nrmVms + 1
self.startVM(cmd, destHostStart)
i += 1
print "Total VMs found: %s" % nrmVms
def startVM(self, cmd, destHostStart):
"""start the VM"""
self.do_connect(destHostStart, VDSM_PORT)
#print cmd
#cmd1 = dict(cmd)
#print cmd1
ret = self.s.create(cmd)
#print ret
print "Triggered VM [%s]" % self.vmName
def usage(self):
"""shows the program params"""
print "Usage: " + sys.argv[0] + " [OPTIONS]"
print "\t--destHost \t Hypervisor host which will start the VM"
print "\t--otherHostsList\t All remaining hosts"
print "\t--vms \t Specify the Names of which VMs to start"
print "\t--version \t List version release"
print "\t--help \t This help menu\n"
print "\t--port \t Specify port to use, default is 54321"
print "Example:"
print ("\t" + sys.argv[0] + " --destHost LinuxSrv1 --otherHostsList" +
" Megatron,Jerry --vms vm1,vm2,vm3,vm4 --port 54321")
sys.exit(1)
if __name__ == "__main__":
otherHostsList = ''
VmsToStart = None
destHostStart = None
VDSM_PORT = 54321
VE = vdsmEmergency()
try:
opts, args = getopt.getopt(sys.argv[1:], "Vd:ho:v:", ["destHost=",
"otherHostsList=", "vms=", "help",
"version", "port"])
except getopt.GetoptError, err:
# print help information and exit:
print(err) # will print something like "option -a not recognized"
VE.usage()
sys.exit(2)
for o, a in opts:
if o in ("-d", "--destHost"):
destHostStart = a
print ""
elif o in ("-h", "--help"):
VE.usage()
sys.exit()
elif o in ("-o", "--otherHostsList"):
otherHostsList = a
elif o in ("-v", "--vms"):
VmsToStart = a
elif o in ("--port"):
VDSM_PORT = a
elif o in ("-V", "--version"):
print VERSION
else:
assert False, "unhandled option"
argc = len(sys.argv)
if argc < 2:
VE.usage()
VE.checkSPM()
# Include the destHost to verify
otherHostsList += ",%s" % destHostStart
VE.checkVmRunning(otherHostsList, VmsToStart)
VE.readXML(VmsToStart, destHostStart)