summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorCory Wright <cory.wright@rackspace.com>2011-04-04 20:41:14 +0000
committerCory Wright <cory.wright@rackspace.com>2011-04-04 20:41:14 +0000
commit545e87bccac95fecf8f86429bd890ed294819487 (patch)
treebd7cde6542d827eac66759cd57375d38d9aefd89 /plugins
parenta4e1db03a2c61648588d9adb703a385f49d82fc0 (diff)
parent08417c48c223ad1b698ab1d00686a967b6a2dc0a (diff)
downloadnova-545e87bccac95fecf8f86429bd890ed294819487.tar.gz
nova-545e87bccac95fecf8f86429bd890ed294819487.tar.xz
nova-545e87bccac95fecf8f86429bd890ed294819487.zip
merge trunk
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/agent83
1 files changed, 77 insertions, 6 deletions
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
index 94eaabe73..5496a6bd5 100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
@@ -22,6 +22,8 @@
# XenAPI plugin for reading/writing information to xenstore
#
+import base64
+import commands
try:
import json
except ImportError:
@@ -66,7 +68,7 @@ def key_init(self, arg_dict):
try:
resp = _wait_for_agent(self, request_id, arg_dict)
except TimeoutError, e:
- raise PluginError("%s" % e)
+ raise PluginError(e)
return resp
@@ -87,7 +89,7 @@ def password(self, arg_dict):
try:
resp = _wait_for_agent(self, request_id, arg_dict)
except TimeoutError, e:
- raise PluginError("%s" % e)
+ raise PluginError(e)
return resp
@@ -102,6 +104,75 @@ def resetnetwork(self, arg_dict):
xenstore.write_record(self, arg_dict)
+@jsonify
+def inject_file(self, arg_dict):
+ """Expects a file path and the contents of the file to be written. Both
+ should be base64-encoded in order to eliminate errors as they are passed
+ through the stack. Writes that information to xenstore for the agent,
+ which will decode the file and intended path, and create it on the
+ instance. The original agent munged both of these into a single entry;
+ the new agent keeps them separate. We will need to test for the new agent,
+ and write the xenstore records to match the agent version. We will also
+ need to test to determine if the file injection method on the agent has
+ been disabled, and raise a NotImplemented error if that is the case.
+ """
+ b64_path = arg_dict["b64_path"]
+ b64_file = arg_dict["b64_file"]
+ request_id = arg_dict["id"]
+ if self._agent_has_method("file_inject"):
+ # New version of the agent. Agent should receive a 'value'
+ # key whose value is a dictionary containing 'b64_path' and
+ # 'b64_file'. See old version below.
+ arg_dict["value"] = json.dumps({"name": "file_inject",
+ "value": {"b64_path": b64_path, "b64_file": b64_file}})
+ elif self._agent_has_method("injectfile"):
+ # Old agent requires file path and file contents to be
+ # combined into one base64 value.
+ raw_path = base64.b64decode(b64_path)
+ raw_file = base64.b64decode(b64_file)
+ new_b64 = base64.b64encode("%s,%s") % (raw_path, raw_file)
+ arg_dict["value"] = json.dumps({"name": "injectfile",
+ "value": new_b64})
+ else:
+ # Either the methods don't exist in the agent, or they
+ # have been disabled.
+ raise NotImplementedError(_("NOT IMPLEMENTED: Agent does not"
+ " support file injection."))
+ arg_dict["path"] = "data/host/%s" % request_id
+ xenstore.write_record(self, arg_dict)
+ try:
+ resp = _wait_for_agent(self, request_id, arg_dict)
+ except TimeoutError, e:
+ raise PluginError(e)
+ return resp
+
+
+def _agent_has_method(self, method):
+ """Check that the agent has a particular method by checking its
+ features. Cache the features so we don't have to query the agent
+ every time we need to check.
+ """
+ try:
+ self._agent_methods
+ except AttributeError:
+ self._agent_methods = []
+ if not self._agent_methods:
+ # Haven't been defined
+ tmp_id = commands.getoutput("uuidgen")
+ dct = {}
+ dct["value"] = json.dumps({"name": "features", "value": ""})
+ dct["path"] = "data/host/%s" % tmp_id
+ xenstore.write_record(self, dct)
+ try:
+ resp = _wait_for_agent(self, tmp_id, dct)
+ except TimeoutError, e:
+ raise PluginError(e)
+ response = json.loads(resp)
+ # The agent returns a comma-separated list of methods.
+ self._agent_methods = response.split(",")
+ return method in self._agent_methods
+
+
def _wait_for_agent(self, request_id, arg_dict):
"""Periodically checks xenstore for a response from the agent.
The request is always written to 'data/host/{id}', and
@@ -119,9 +190,8 @@ def _wait_for_agent(self, request_id, arg_dict):
# First, delete the request record
arg_dict["path"] = "data/host/%s" % request_id
xenstore.delete_record(self, arg_dict)
- raise TimeoutError(
- "TIMEOUT: No response from agent within %s seconds." %
- AGENT_TIMEOUT)
+ raise TimeoutError(_("TIMEOUT: No response from agent within"
+ " %s seconds.") % AGENT_TIMEOUT)
ret = xenstore.read_record(self, arg_dict)
# Note: the response for None with be a string that includes
# double quotes.
@@ -136,4 +206,5 @@ if __name__ == "__main__":
XenAPIPlugin.dispatch(
{"key_init": key_init,
"password": password,
- "resetnetwork": resetnetwork})
+ "resetnetwork": resetnetwork,
+ "inject_file": inject_file})