Add ed leafe's code for the inject_file agent plugin method that somehow got lost (fixes bug 741246).
Update TimeoutError string for i18n
This commit is contained in:
parent
f77c58ce31
commit
a1992ba586
@ -22,6 +22,7 @@
|
||||
# XenAPI plugin for reading/writing information to xenstore
|
||||
#
|
||||
|
||||
import base64
|
||||
try:
|
||||
import json
|
||||
except ImportError:
|
||||
@ -31,6 +32,7 @@ import random
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import XenAPIPlugin
|
||||
|
||||
@ -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("%s" % 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 = str(uuid.uuid4())
|
||||
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("%s" % 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})
|
||||
|
Loading…
Reference in New Issue
Block a user