Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
CIRCLE
/
vmdriver
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
2
Merge Requests
0
Wiki
Members
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
6a91b611
authored
Nov 08, 2013
by
Guba Sándor
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
vmdriver: static connection class and fixing pep issues.
parent
a99cac51
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
159 additions
and
78 deletions
+159
-78
vmdriver.py
+159
-78
No files found.
vmdriver.py
View file @
6a91b611
""" Driver for libvirt. """
import
libvirt
import
libvirt
import
logging
import
logging
import
os
import
os
...
@@ -8,7 +9,6 @@ from vmcelery import celery, lib_connection
...
@@ -8,7 +9,6 @@ from vmcelery import celery, lib_connection
sys
.
path
.
append
(
os
.
path
.
dirname
(
os
.
path
.
basename
(
__file__
)))
sys
.
path
.
append
(
os
.
path
.
dirname
(
os
.
path
.
basename
(
__file__
)))
connection
=
None
state_dict
=
{
0
:
'NOSTATE'
,
state_dict
=
{
0
:
'NOSTATE'
,
1
:
'RUNNING'
,
1
:
'RUNNING'
,
...
@@ -21,16 +21,51 @@ state_dict = {0: 'NOSTATE',
...
@@ -21,16 +21,51 @@ state_dict = {0: 'NOSTATE',
}
}
#class Singleton(type):
#
# """ Singleton class."""
#
# _instances = {}
#
# def __call__(cls, *args, **kwargs):
# if cls not in cls._instances:
# cls._instances[cls] = super(Singleton, cls).__call__(*args,
# **kwargs)
# return cls._instances[cls]
class
Connection
(
object
):
""" Singleton class to handle connection."""
# __metaclass__ = Singleton
connection
=
None
@classmethod
def
get
(
cls
):
""" Return the libvirt connection."""
return
cls
.
connection
@classmethod
def
set
(
cls
,
connection
):
""" Set the libvirt connection."""
cls
.
connection
=
connection
@decorator
@decorator
def
req_connection
(
original_function
,
*
args
,
**
kw
):
def
req_connection
(
original_function
,
*
args
,
**
kw
):
'''Connection checking decorator for libvirt.
"""Connection checking decorator for libvirt.
If envrionment variable LIBVIRT_KEEPALIVE is set
it will use the connection from the celery worker.
Return the decorateed function
If envrionment variable LIBVIRT_KEEPALIVE is set
"""
it will use the connection from the celery worker.
'''
logging
.
debug
(
"Decorator running"
)
logging
.
debug
(
"Decorator running"
)
global
connection
if
Connection
.
get
()
is
None
:
if
connection
is
None
:
connect
()
connect
()
try
:
try
:
logging
.
debug
(
"Decorator calling original function"
)
logging
.
debug
(
"Decorator calling original function"
)
...
@@ -48,6 +83,11 @@ def req_connection(original_function, *args, **kw):
...
@@ -48,6 +83,11 @@ def req_connection(original_function, *args, **kw):
@decorator
@decorator
def
wrap_libvirtError
(
original_function
,
*
args
,
**
kw
):
def
wrap_libvirtError
(
original_function
,
*
args
,
**
kw
):
""" Decorator to wrap libvirt error in simple Exception.
Return decorated function
"""
try
:
try
:
return
original_function
(
*
args
,
**
kw
)
return
original_function
(
*
args
,
**
kw
)
except
libvirt
.
libvirtError
as
e
:
except
libvirt
.
libvirtError
as
e
:
...
@@ -60,34 +100,34 @@ def wrap_libvirtError(original_function, *args, **kw):
...
@@ -60,34 +100,34 @@ def wrap_libvirtError(original_function, *args, **kw):
@celery.task
@celery.task
@wrap_libvirtError
@wrap_libvirtError
def
connect
(
connection_string
=
'qemu:///system'
):
def
connect
(
connection_string
=
'qemu:///system'
):
'''Connect to the libvirt daemon specified in the
""" Connect to the libvirt daemon.
connection_string or the local root.
'''
String is specified in the connection_string parameter
global
connection
the default is the local root.
"""
if
os
.
getenv
(
'LIBVIRT_KEEPALIVE'
)
is
None
:
if
os
.
getenv
(
'LIBVIRT_KEEPALIVE'
)
is
None
:
if
connection
is
None
:
if
Connection
.
get
()
is
None
:
connection
=
libvirt
.
open
(
connection_string
)
Connection
.
set
(
libvirt
.
open
(
connection_string
)
)
logging
.
debug
(
"Connection estabilished to libvirt."
)
logging
.
debug
(
"Connection estabilished to libvirt."
)
else
:
else
:
logging
.
debug
(
"There is already an active connection to libvirt."
)
logging
.
debug
(
"There is already an active connection to libvirt."
)
else
:
else
:
connection
=
lib_connection
Connection
.
set
(
lib_connection
)
logging
.
debug
(
"Using celery libvirt connection connection."
)
logging
.
debug
(
"Using celery libvirt connection connection."
)
@celery.task
@celery.task
@wrap_libvirtError
@wrap_libvirtError
def
disconnect
():
def
disconnect
():
'''Disconnect from the active libvirt daemon connection.
""" Disconnect from the active libvirt daemon connection."""
'''
global
connection
if
os
.
getenv
(
'LIBVIRT_KEEPALIVE'
)
is
None
:
if
os
.
getenv
(
'LIBVIRT_KEEPALIVE'
)
is
None
:
if
connection
is
None
:
if
Connection
.
get
()
is
None
:
logging
.
debug
(
'There is no available libvirt conection.'
)
logging
.
debug
(
'There is no available libvirt conection.'
)
else
:
else
:
connection
.
close
()
Connection
.
get
()
.
close
()
logging
.
debug
(
'Connection closed to libvirt.'
)
logging
.
debug
(
'Connection closed to libvirt.'
)
connection
=
None
Connection
.
set
(
None
)
else
:
else
:
logging
.
debug
(
'Keepalive connection should not close.'
)
logging
.
debug
(
'Keepalive connection should not close.'
)
...
@@ -96,9 +136,8 @@ def disconnect():
...
@@ -96,9 +136,8 @@ def disconnect():
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
define
(
vm
):
def
define
(
vm
):
'''Define permanent virtual machine from xml
""" Define permanent virtual machine from xml. """
'''
Connection
.
get
()
.
defineXML
(
vm
.
dump_xml
())
connection
.
defineXML
(
vm
.
dump_xml
())
logging
.
info
(
"Virtual machine
%
s is defined from xml"
,
vm
.
name
)
logging
.
info
(
"Virtual machine
%
s is defined from xml"
,
vm
.
name
)
...
@@ -106,14 +145,17 @@ def define(vm):
...
@@ -106,14 +145,17 @@ def define(vm):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
create
(
vm_desc
):
def
create
(
vm_desc
):
'''Create and start non-permanent virtual machine from xml
""" Create and start non-permanent virtual machine from xml.
Return the domain info dict.
flags can be:
flags can be:
VIR_DOMAIN_NONE = 0
VIR_DOMAIN_NONE = 0
VIR_DOMAIN_START_PAUSED = 1
VIR_DOMAIN_START_PAUSED = 1
VIR_DOMAIN_START_AUTODESTROY = 2
VIR_DOMAIN_START_AUTODESTROY = 2
VIR_DOMAIN_START_BYPASS_CACHE = 4
VIR_DOMAIN_START_BYPASS_CACHE = 4
VIR_DOMAIN_START_FORCE_BOOT = 8
VIR_DOMAIN_START_FORCE_BOOT = 8
'''
"""
vm
=
VMInstance
.
deserialize
(
vm_desc
)
vm
=
VMInstance
.
deserialize
(
vm_desc
)
# Setting proper hypervisor
# Setting proper hypervisor
vm
.
vm_type
=
os
.
getenv
(
"HYPERVISOR_TYPE"
,
"test"
)
vm
.
vm_type
=
os
.
getenv
(
"HYPERVISOR_TYPE"
,
"test"
)
...
@@ -121,15 +163,15 @@ def create(vm_desc):
...
@@ -121,15 +163,15 @@ def create(vm_desc):
logging
.
info
(
xml
)
logging
.
info
(
xml
)
# Emulating DOMAIN_START_PAUSED FLAG behaviour on test driver
# Emulating DOMAIN_START_PAUSED FLAG behaviour on test driver
if
vm
.
vm_type
==
"test"
:
if
vm
.
vm_type
==
"test"
:
connection
.
createXML
(
Connection
.
get
()
.
createXML
(
xml
,
libvirt
.
VIR_DOMAIN_NONE
)
xml
,
libvirt
.
VIR_DOMAIN_NONE
)
domain
=
lookupByName
(
vm
.
name
)
domain
=
lookupByName
(
vm
.
name
)
domain
.
suspend
()
domain
.
suspend
()
# Real driver create
# Real driver create
else
:
else
:
connection
.
createXML
(
Connection
.
get
()
.
createXML
(
vm
.
dump_xml
(),
libvirt
.
VIR_DOMAIN_START_PAUSED
)
vm
.
dump_xml
(),
libvirt
.
VIR_DOMAIN_START_PAUSED
)
logging
.
info
(
"Virtual machine
%
s is created from xml"
,
vm
.
name
)
logging
.
info
(
"Virtual machine
%
s is created from xml"
,
vm
.
name
)
return
domain_info
(
vm
.
name
)
return
domain_info
(
vm
.
name
)
...
@@ -137,19 +179,17 @@ def create(vm_desc):
...
@@ -137,19 +179,17 @@ def create(vm_desc):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
shutdown
(
name
):
def
shutdown
(
name
):
'''Shutdown virtual machine (need ACPI support).
""" Shutdown virtual machine (need ACPI support). """
'''
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
shutdown
()
domain
.
shutdown
()
return
_parse_info
(
domain
.
info
())
@celery.task
@celery.task
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
delete
(
name
):
def
delete
(
name
):
'''Destroy the running called 'name' virtual machine.
""" Destroy the running called 'name' virtual machine. """
'''
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
destroy
()
domain
.
destroy
()
...
@@ -158,12 +198,14 @@ def delete(name):
...
@@ -158,12 +198,14 @@ def delete(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
list_domains
():
def
list_domains
():
'''
""" List the running domains.
:return list: List of domains name in host
'''
:return list: List of domains name in host.
"""
domain_list
=
[]
domain_list
=
[]
for
i
in
connection
.
listDomainsID
():
for
i
in
Connection
.
get
()
.
listDomainsID
():
dom
=
connection
.
lookupByID
(
i
)
dom
=
Connection
.
get
()
.
lookupByID
(
i
)
domain_list
.
append
(
dom
.
name
())
domain_list
.
append
(
dom
.
name
())
return
domain_list
return
domain_list
...
@@ -172,18 +214,19 @@ def list_domains():
...
@@ -172,18 +214,19 @@ def list_domains():
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
lookupByName
(
name
):
def
lookupByName
(
name
):
'''Return with the requested Domain
""" Return with the requested Domain. """
'''
return
Connection
.
get
()
.
lookupByName
(
name
)
return
connection
.
lookupByName
(
name
)
@celery.task
@celery.task
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
undefine
(
name
):
def
undefine
(
name
):
'''Undefine an already defined virtual machine.
""" Undefine an already defined virtual machine.
If it's running it becomes transient (lsot on reboot)
'''
If it's running it becomes transient (lost on reboot)
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
undefine
()
domain
.
undefine
()
...
@@ -192,8 +235,8 @@ def undefine(name):
...
@@ -192,8 +235,8 @@ def undefine(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
start
(
name
):
def
start
(
name
):
'''Start an already defined virtual machine.
""" Start an already defined virtual machine."""
'''
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
create
()
domain
.
create
()
...
@@ -202,8 +245,12 @@ def start(name):
...
@@ -202,8 +245,12 @@ def start(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
suspend
(
name
):
def
suspend
(
name
):
'''Stop virtual machine and keep memory in RAM.
""" Stop virtual machine and keep memory in RAM.
'''
Return the domain info dict.
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
suspend
()
domain
.
suspend
()
return
_parse_info
(
domain
.
info
())
return
_parse_info
(
domain
.
info
())
...
@@ -213,8 +260,8 @@ def suspend(name):
...
@@ -213,8 +260,8 @@ def suspend(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
save
(
name
,
path
):
def
save
(
name
,
path
):
'''Stop virtual machine and save its memory to path.
""" Stop virtual machine and save its memory to path. """
'''
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
save
(
path
)
domain
.
save
(
path
)
...
@@ -223,9 +270,14 @@ def save(name, path):
...
@@ -223,9 +270,14 @@ def save(name, path):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
restore
(
name
,
path
):
def
restore
(
name
,
path
):
'''Restore a saved virtual machine
""" Restore a saved virtual machine.
from the memory image stored at path.'''
connection
.
restore
(
path
)
Restores the virtual machine from the memory image
stored at path.
Return the domain info dict.
"""
Connection
.
get
()
.
restore
(
path
)
return
domain_info
(
name
)
return
domain_info
(
name
)
...
@@ -233,8 +285,12 @@ def restore(name, path):
...
@@ -233,8 +285,12 @@ def restore(name, path):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
resume
(
name
):
def
resume
(
name
):
'''Resume stopped virtual machines.
""" Resume stopped virtual machines.
'''
Return the domain info dict.
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
resume
()
domain
.
resume
()
return
_parse_info
(
domain
.
info
())
return
_parse_info
(
domain
.
info
())
...
@@ -244,8 +300,12 @@ def resume(name):
...
@@ -244,8 +300,12 @@ def resume(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
reset
(
name
):
def
reset
(
name
):
'''Reset (power reset) virtual machine.
""" Reset (power reset) virtual machine.
'''
Return the domain info dict.
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
reset
()
domain
.
reset
()
return
_parse_info
(
domain
.
info
())
return
_parse_info
(
domain
.
info
())
...
@@ -255,8 +315,11 @@ def reset(name):
...
@@ -255,8 +315,11 @@ def reset(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
reboot
(
name
):
def
reboot
(
name
):
'''Reboot (with guest acpi support) virtual machine.
""" Reboot (with guest acpi support) virtual machine.
'''
Return the domain info dict.
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
reboot
()
domain
.
reboot
()
return
_parse_info
(
domain
.
info
())
return
_parse_info
(
domain
.
info
())
...
@@ -266,7 +329,10 @@ def reboot(name):
...
@@ -266,7 +329,10 @@ def reboot(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
node_info
():
def
node_info
():
''' Get info from Host as dict:
""" Get info from Host as dict.
Return dict:
model string indicating the CPU model
model string indicating the CPU model
memory memory size in kilobytes
memory memory size in kilobytes
cpus the number of active CPUs
cpus the number of active CPUs
...
@@ -279,15 +345,22 @@ def node_info():
...
@@ -279,15 +345,22 @@ def node_info():
cores number of cores per socket, total number of
cores number of cores per socket, total number of
processors in case of unusual NUMA topolog
processors in case of unusual NUMA topolog
threads number of threads per core, 1 in case of unusual numa topology
threads number of threads per core, 1 in case of unusual numa topology
'''
"""
keys
=
[
'model'
,
'memory'
,
'cpus'
,
'mhz'
,
keys
=
[
'model'
,
'memory'
,
'cpus'
,
'mhz'
,
'nodes'
,
'sockets'
,
'cores'
,
'threads'
]
'nodes'
,
'sockets'
,
'cores'
,
'threads'
]
values
=
connection
.
getInfo
()
values
=
Connection
.
get
()
.
getInfo
()
return
dict
(
zip
(
keys
,
values
))
return
dict
(
zip
(
keys
,
values
))
def
_parse_info
(
values
):
def
_parse_info
(
values
):
'''Parse libvirt domain info into dict'''
""" Parse libvirt domain info into dict.
Return the info dict.
"""
keys
=
[
'state'
,
'maxmem'
,
'memory'
,
'virtcpunum'
,
'cputime'
]
keys
=
[
'state'
,
'maxmem'
,
'memory'
,
'virtcpunum'
,
'cputime'
]
info
=
dict
(
zip
(
keys
,
values
))
info
=
dict
(
zip
(
keys
,
values
))
# Change state to proper ENUM
# Change state to proper ENUM
...
@@ -299,13 +372,16 @@ def _parse_info(values):
...
@@ -299,13 +372,16 @@ def _parse_info(values):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
domain_info
(
name
):
def
domain_info
(
name
):
'''
""" Get the domain info from libvirt.
Return the domain info dict:
state the running state, one of virDomainState
state the running state, one of virDomainState
maxmem the maximum memory in KBytes allowed
maxmem the maximum memory in KBytes allowed
memory the memory in KBytes used by the domain
memory the memory in KBytes used by the domain
virtcpunum the number of virtual CPUs for the domain
virtcpunum the number of virtual CPUs for the domain
cputime the CPU time used in nanoseconds
cputime the CPU time used in nanoseconds
'''
"""
dom
=
lookupByName
(
name
)
dom
=
lookupByName
(
name
)
return
_parse_info
(
dom
.
info
())
return
_parse_info
(
dom
.
info
())
...
@@ -314,7 +390,8 @@ def domain_info(name):
...
@@ -314,7 +390,8 @@ def domain_info(name):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
network_info
(
name
,
network
):
def
network_info
(
name
,
network
):
'''
""" Return the network info dict.
rx_bytes
rx_bytes
rx_packets
rx_packets
rx_errs
rx_errs
...
@@ -323,7 +400,8 @@ def network_info(name, network):
...
@@ -323,7 +400,8 @@ def network_info(name, network):
tx_packets
tx_packets
tx_errs
tx_errs
tx_drop
tx_drop
'''
"""
keys
=
[
'rx_bytes'
,
'rx_packets'
,
'rx_errs'
,
'rx_drop'
,
keys
=
[
'rx_bytes'
,
'rx_packets'
,
'rx_errs'
,
'rx_drop'
,
'tx_bytes'
,
'tx_packets'
,
'tx_errs'
,
'tx_drop'
]
'tx_bytes'
,
'tx_packets'
,
'tx_errs'
,
'tx_drop'
]
dom
=
lookupByName
(
name
)
dom
=
lookupByName
(
name
)
...
@@ -336,10 +414,12 @@ def network_info(name, network):
...
@@ -336,10 +414,12 @@ def network_info(name, network):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
send_key
(
name
,
key_code
):
def
send_key
(
name
,
key_code
):
''' Sending linux key_code to the name vm
""" Sending linux key_code to the name vm.
key_code can be optained from linux_keys.py
e.x: linuxkeys.KEY_RIGHTCTRL
key_code can be optained from linux_keys.py
'''
e.x: linuxkeys.KEY_RIGHTCTRL
"""
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
domain
.
sendKey
(
libvirt
.
VIR_KEYCODE_SET_LINUX
,
100
,
[
key_code
],
1
,
0
)
domain
.
sendKey
(
libvirt
.
VIR_KEYCODE_SET_LINUX
,
100
,
[
key_code
],
1
,
0
)
...
@@ -353,19 +433,20 @@ def _stream_handler(stream, buf, opaque):
...
@@ -353,19 +433,20 @@ def _stream_handler(stream, buf, opaque):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
screenshot
(
name
,
path
):
def
screenshot
(
name
,
path
):
"""Save screenshot of virtual machine
"""Save screenshot of virtual machine.
to the path as name-screenshot.ppm
Image is saved to the path as name-screenshot.ppm
"""
"""
# Import linuxkeys to get defines
# Import linuxkeys to get defines
import
linuxkeys
import
linuxkeys
# Connection need for the stream object
# Connection need for the stream object
global
connection
domain
=
lookupByName
(
name
)
domain
=
lookupByName
(
name
)
# Send key to wake up console
# Send key to wake up console
domain
.
sendKey
(
libvirt
.
VIR_KEYCODE_SET_LINUX
,
domain
.
sendKey
(
libvirt
.
VIR_KEYCODE_SET_LINUX
,
100
,
[
linuxkeys
.
KEY_RIGHTCTRL
],
1
,
0
)
100
,
[
linuxkeys
.
KEY_RIGHTCTRL
],
1
,
0
)
# Create Stream to get data
# Create Stream to get data
stream
=
connection
.
newStream
(
0
)
stream
=
Connection
.
get
()
.
newStream
(
0
)
# Take screenshot accessible by stream (return mimetype)
# Take screenshot accessible by stream (return mimetype)
domain
.
screenshot
(
stream
,
0
,
0
)
domain
.
screenshot
(
stream
,
0
,
0
)
# Get file to save data (TODO: send on AMQP?)
# Get file to save data (TODO: send on AMQP?)
...
@@ -383,7 +464,7 @@ def screenshot(name, path):
...
@@ -383,7 +464,7 @@ def screenshot(name, path):
@req_connection
@req_connection
@wrap_libvirtError
@wrap_libvirtError
def
migrate
(
name
,
host
,
live
=
False
):
def
migrate
(
name
,
host
,
live
=
False
):
'''Migrate domain to host'''
""" Migrate domain to host. """
flags
=
libvirt
.
VIR_MIGRATE_PEER2PEER
flags
=
libvirt
.
VIR_MIGRATE_PEER2PEER
if
live
:
if
live
:
flags
=
flags
|
libvirt
.
VIR_MIGRATE_LIVE
flags
=
flags
|
libvirt
.
VIR_MIGRATE_LIVE
...
@@ -393,4 +474,4 @@ def migrate(name, host, live=False):
...
@@ -393,4 +474,4 @@ def migrate(name, host, live=False):
flags
=
flags
,
flags
=
flags
,
dname
=
name
,
dname
=
name
,
bandwidth
=
0
)
bandwidth
=
0
)
#return _parse_info(domain.info())
#
return _parse_info(domain.info())
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment