Add logging, error handling to the xenstore lib.

Change-Id: If007ba117105d63b1eecfee5b8941d98032d2c9a
This commit is contained in:
Mark Washenberger 2011-11-14 16:41:14 -05:00
parent 80ffed4f0a
commit c51104ab01

View File

@ -26,6 +26,8 @@ try:
import json import json
except ImportError: except ImportError:
import simplejson as json import simplejson as json
import logging
import os
import subprocess import subprocess
import XenAPIPlugin import XenAPIPlugin
@ -34,6 +36,19 @@ import pluginlib_nova as pluginlib
pluginlib.configure_logging("xenstore") pluginlib.configure_logging("xenstore")
class XenstoreError(pluginlib.PluginError):
"""Errors that occur when calling xenstore-* through subprocesses"""
def __init__(self, cmd, return_code, stderr, stdout):
msg = "cmd: %s; returncode: %d; stderr: %s; stdout: %s"
msg = msg % (cmd, return_code, stderr, stdout)
self.cmd = cmd
self.return_code = return_code
self.stderr = stderr
self.stdout = stdout
pluginlib.PluginError.__init__(self, msg)
def jsonify(fnc): def jsonify(fnc):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
ret = fnc(*args, **kwargs) ret = fnc(*args, **kwargs)
@ -48,6 +63,21 @@ def jsonify(fnc):
return wrapper return wrapper
def _record_exists(arg_dict):
"""Returns whether or not the given record exists. The record path
is determined from the given path and dom_id in the arg_dict."""
cmd = ["xenstore-exists", "/local/domain/%(dom_id)s/%(path)s" % arg_dict]
try:
ret, result = _run_command(cmd)
except XenstoreError, e:
if e.stderr == '':
# if stderr was empty, this just means the path did not exist
return False
# otherwise there was a real problem
raise
return True
@jsonify @jsonify
def read_record(self, arg_dict): def read_record(self, arg_dict):
"""Returns the value stored at the given path for the given dom_id. """Returns the value stored at the given path for the given dom_id.
@ -60,16 +90,9 @@ def read_record(self, arg_dict):
try: try:
ret, result = _run_command(cmd) ret, result = _run_command(cmd)
return result.strip() return result.strip()
except pluginlib.PluginError, e: except XenstoreError, e:
if arg_dict.get("ignore_missing_path", False): if arg_dict.get("ignore_missing_path", False):
cmd = ["xenstore-exists", if not _record_exists(arg_dict):
"/local/domain/%(dom_id)s/%(path)s" % arg_dict]
ret, result = _run_command(cmd)
# If the path exists, the cmd should return "0"
if ret != 0:
# No such path, so ignore the error and return the
# string 'None', since None can't be marshalled
# over RPC.
return "None" return "None"
# Either we shouldn't ignore path errors, or another # Either we shouldn't ignore path errors, or another
# error was hit. Re-raise. # error was hit. Re-raise.
@ -102,11 +125,9 @@ def list_records(self, arg_dict):
cmd = ["xenstore-ls", dirpath.rstrip("/")] cmd = ["xenstore-ls", dirpath.rstrip("/")]
try: try:
ret, recs = _run_command(cmd) ret, recs = _run_command(cmd)
except pluginlib.PluginError, e: except XenstoreError, e:
if "No such file or directory" in "%s" % e: if not _record_exists(arg_dict):
# Path doesn't exist.
return {} return {}
return str(e)
raise raise
base_path = arg_dict["path"] base_path = arg_dict["path"]
paths = _paths_from_ls(recs) paths = _paths_from_ls(recs)
@ -173,14 +194,14 @@ def _run_command(cmd):
returns anything in stderr, a PluginError is raised with that information. returns anything in stderr, a PluginError is raised with that information.
Otherwise, a tuple of (return code, stdout data) is returned. Otherwise, a tuple of (return code, stdout data) is returned.
""" """
logging.info(' '.join(cmd))
pipe = subprocess.PIPE pipe = subprocess.PIPE
proc = subprocess.Popen(cmd, stdin=pipe, stdout=pipe, stderr=pipe, proc = subprocess.Popen(cmd, stdin=pipe, stdout=pipe, stderr=pipe,
close_fds=True) close_fds=True)
ret = proc.wait() out, err = proc.communicate()
err = proc.stderr.read() if proc.returncode is not os.EX_OK:
if err: raise XenstoreError(cmd, proc.returncode, err, out)
raise pluginlib.PluginError(err) return proc.returncode, out
return (ret, proc.stdout.read())
if __name__ == "__main__": if __name__ == "__main__":