Newer
Older
'''
All KVM technology specefic functions are implemented inside this module
Two entites belong to this module: a Kvm hypervisor or a Kvm virtual machine
'''
from libvirtwrapper import *
from exceptions import *
Benziane Chakib
committed
import hashlib
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
class KvmHypervisor(LibvirtHypervisor):
'''
Base class of a Kvm Hypervisor
This class have a attribute hv_type for tagging purposes
'''
_instance = None
def __init__(self):
super(KvmHypervisor, self).__init__('kvm')
self.hv_type = 'KVM/QEMU'
def __new__(cls, *args, **kwargs):
'''
.. note::
We use singleton design pattern to force only a single instance
of ourlibvirt hypervisor handle, it's essential since we connect
with libvirt only on localhost so we must assure one single
connection to the hypervisor
'''
if cls._instance is None:
cls._instance = super(KvmHypervisor, cls).__new__(cls, *args,
**kwargs)
return cls._instance
def start_vm(self, name, start_options=DEFAULT_VM_START):
'''
Starts the vm identified by name
:param name: The name of the virtual machine
:type nane: :class:`str`
:param start_options: Options flags while starting vm
:type start_options: TODO reference to constants
'''
for vm in self._vm_list:
if vm.get_name() == name:
vm.start()
return
raise VMError('Virtual Machine %s not found: '% name)
def stop_vm(self, name, force=False):
'''
Poweroff the specifed vm with the specified options
:param name: the name of the vm
:type name: :class:`str`
'''
for vm in self._vm_list:
if vm.get_name() == name:
vm.force_poweroff() if force else vm.shutdown()
raise VMError('Virtual Machine %s not found: ' % name)
def suspend_vm(self, name):
'''
Suspends the specifed vm
:param name: the name of the vm
:type name: :class:`str`
'''
for vm in self._vm_list:
if vm.get_name() == name:
vm.suspend()
return
raise VMError('Virtual machine %s not found: ' % name)
def resume_vm(self, name):
'''
Resumes the specifed vm
:param name: the name of the vm
:type name: :class:`str`
'''
for vm in self._vm_list:
if vm.get_name() == name:
vm.resume()
return
raise VMError('Virtual machine %s not found: ' % name)
'''
Excecutes the command given in command on the local host
Returns a tuple with (stdout, stderr) from the process that has
been executed
..warning:: This is a dangerous function as it gives the command given
in paramter to a shell prompt, anything can then be executed locally
..warning:: If the command given is a long processing one, this may be
a deadlock to the node be carefull !
:param command: the command to execute with it's arguments
:type command: :class:`str`
'''
#FIXME: stop using shell=true and parse arguments with shlex.split()
p = subprocess.Popen(command, shell=True,
Benziane Chakib
committed
bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
result = p.communicate()
return result
Benziane Chakib
committed
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
def export_vm(self, name, target, port):
'''
Migrates the given vm (name) to (target) hypervisor which is already
waiting for the migration
:param name: the name of the vm
:type name: :class:`str`
:param target: the destination hypervisor
:type target: :class:`str`
:param port: the port on the destination to use for the transfer
:type port: :class:`str`
'''
# We will be using subprocess to pipe the volume using dd in a netcat
# connection to the destination
# We send a hash of the volume before so that the target can checksum
# and validate integrity.
# This algorithm is just a proof of concept of the cold migration
# process it is likely that it does not anticipates some problems
buff = 1024 * 1024 * 10 #10 Mo
path = [vm.get_disk_path() for vm in self._vm_list
if vm.get_name() == name].pop()
dd_cmd = ['dd', 'if=%s' % path]
dd_process = subprocess.Popen(dd_cmd, bufsize=-1,
stdout=subprocess.PIPE)
nc_process = subprocess.Popen(['nc', target, port],
bufsize=-1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
#We send dd output to nc
dd_out = dd_process.stdout
nc_in = nc_process.stdin
m = hashlib.md5()
print 'going to pipe loop'
try:
read = dd_out.read(buff)
except Exception as err:
raise IOError('error while reading dd process output %s' % err)
try:
while len(read) != 0:
print len(read)
m.update(read)
nc_in.write(read)
nc_in.flush()
read = dd_out.read(buff)
except Exception as err:
raise IOError('Error occured while writing to nc process %s' % err)
nc_in.close()
print m.hexdigest()