Add logging, error handling to the xenstore lib.
Change-Id: If007ba117105d63b1eecfee5b8941d98032d2c9a
This commit is contained in:
parent
80ffed4f0a
commit
c51104ab01
@ -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__":
|
||||||
|
Loading…
Reference in New Issue
Block a user