Redfish-simulator: Do not cache the connection

This patch is changing the libvirt mockup script to open a new
connection with libvirt everything it needs to talk to it. Prior to it
we were caching the connection but the downside of it was that every
time the libvirt service was restarted (and it happens a couple of times
when setting up DevStack with Ironic) the simulator stopped working.

Change-Id: I94a656a91ef6d81dd2cfc52c65180beadfdcd295
Closes-Bug: #1672666
This commit is contained in:
Lucas Alvares Gomes 2017-03-14 10:42:03 +00:00
parent d377b545a0
commit 39f9db1245
1 changed files with 77 additions and 48 deletions

View File

@ -26,7 +26,7 @@ app = flask.Flask(__name__)
# Turn off strict_slashes on all routes
app.url_map.strict_slashes = False
LIBVIRT_CONN = None
LIBVIRT_URI = None
BOOT_DEVICE_MAP = {
'Pxe': 'network',
@ -37,9 +37,30 @@ BOOT_DEVICE_MAP = {
BOOT_DEVICE_MAP_REV = {v: k for k, v in BOOT_DEVICE_MAP.items()}
def _get_libvirt_domain(domain):
class libvirt_open(object):
def __init__(self, uri, readonly=False):
self.uri = uri
self.readonly = readonly
def __enter__(self):
try:
self._conn = (libvirt.openReadOnly(self.uri)
if self.readonly else
libvirt.open(self.uri))
return self._conn
except libvirt.libvirtError as e:
print('Error when connecting to the libvirt URI "%(uri)s": '
'%(error)s' % {'uri': self.uri, 'error': e})
flask.abort(500)
def __exit__(self, type, value, traceback):
self._conn.close()
def get_libvirt_domain(connection, domain):
try:
return LIBVIRT_CONN.lookupByName(domain)
return connection.lookupByName(domain)
except libvirt.libvirtError:
flask.abort(404)
@ -51,9 +72,11 @@ def root_resource():
@app.route('/redfish/v1/Systems')
def system_collection_resource():
domains = LIBVIRT_CONN.listDefinedDomains()
return flask.render_template(
'system_collection.json', system_count=len(domains), systems=domains)
with libvirt_open(LIBVIRT_URI, readonly=True) as conn:
domains = conn.listDefinedDomains()
return flask.render_template(
'system_collection.json', system_count=len(domains),
systems=domains)
def _get_total_cpus(domain, tree):
@ -81,19 +104,20 @@ def _get_boot_source_target(tree):
@app.route('/redfish/v1/Systems/<identity>', methods=['GET', 'PATCH'])
def system_resource(identity):
domain = _get_libvirt_domain(identity)
if flask.request.method == 'GET':
power_state = 'On' if domain.isActive() else 'Off'
total_memory_gb = int(domain.maxMemory() / 1024 / 1024)
with libvirt_open(LIBVIRT_URI, readonly=True) as conn:
domain = get_libvirt_domain(conn, identity)
power_state = 'On' if domain.isActive() else 'Off'
total_memory_gb = int(domain.maxMemory() / 1024 / 1024)
tree = ET.fromstring(domain.XMLDesc())
total_cpus = _get_total_cpus(domain, tree)
boot_source_target = _get_boot_source_target(tree)
tree = ET.fromstring(domain.XMLDesc())
total_cpus = _get_total_cpus(domain, tree)
boot_source_target = _get_boot_source_target(tree)
return flask.render_template(
'system.json', identity=identity, uuid=domain.UUIDString(),
power_state=power_state, total_memory_gb=total_memory_gb,
total_cpus=total_cpus, boot_source_target=boot_source_target)
return flask.render_template(
'system.json', identity=identity, uuid=domain.UUIDString(),
power_state=power_state, total_memory_gb=total_memory_gb,
total_cpus=total_cpus, boot_source_target=boot_source_target)
elif flask.request.method == 'PATCH':
boot = flask.request.json.get('Boot')
@ -111,45 +135,50 @@ def system_resource(identity):
# TODO(lucasagomes): We should allow changing the boot mode from
# BIOS to UEFI (and vice-versa)
tree = ET.fromstring(domain.XMLDesc())
for os_element in tree.findall('os'):
# Remove all "boot" elements
for boot_element in os_element.findall('boot'):
os_element.remove(boot_element)
with libvirt_open(LIBVIRT_URI) as conn:
domain = get_libvirt_domain(conn, identity)
tree = ET.fromstring(domain.XMLDesc())
for os_element in tree.findall('os'):
# Remove all "boot" elements
for boot_element in os_element.findall('boot'):
os_element.remove(boot_element)
# Add a new boot element with the request boot device
boot_element = ET.SubElement(os_element, 'boot')
boot_element.set('dev', target)
conn.defineXML(ET.tostring(tree).decode('utf-8'))
# Add a new boot element with the request boot device
boot_element = ET.SubElement(os_element, 'boot')
boot_element.set('dev', target)
LIBVIRT_CONN.defineXML(ET.tostring(tree).decode('utf-8'))
return '', 204
@app.route('/redfish/v1/Systems/<identity>/Actions/ComputerSystem.Reset',
methods=['POST'])
def system_reset_action(identity):
domain = _get_libvirt_domain(identity)
reset_type = flask.request.json.get('ResetType')
try:
if reset_type in ('On', 'ForceOn'):
if not domain.isActive():
domain.create()
elif reset_type == 'ForceOff':
if domain.isActive():
domain.destroy()
elif reset_type == 'GracefulShutdown':
if domain.isActive():
domain.shutdown()
elif reset_type == 'GracefulRestart':
if domain.isActive():
domain.reboot()
elif reset_type == 'ForceRestart':
if domain.isActive():
domain.reset()
elif reset_type == 'Nmi':
if domain.isActive():
domain.injectNMI()
except libvirt.libvirtError:
flask.abort(500)
with libvirt_open(LIBVIRT_URI) as conn:
domain = get_libvirt_domain(conn, identity)
try:
if reset_type in ('On', 'ForceOn'):
if not domain.isActive():
domain.create()
elif reset_type == 'ForceOff':
if domain.isActive():
domain.destroy()
elif reset_type == 'GracefulShutdown':
if domain.isActive():
domain.shutdown()
elif reset_type == 'GracefulRestart':
if domain.isActive():
domain.reboot()
elif reset_type == 'ForceRestart':
if domain.isActive():
domain.reset()
elif reset_type == 'Nmi':
if domain.isActive():
domain.injectNMI()
except libvirt.libvirtError:
flask.abort(500)
return '', 204
@ -175,7 +204,7 @@ def parse_args():
if __name__ == '__main__':
args = parse_args()
LIBVIRT_CONN = libvirt.open(args.libvirt_uri)
LIBVIRT_URI = args.libvirt_uri
ssl_context = None
if args.ssl_certificate and args.ssl_key: