From 6c3a8e16fb1347b0b5ecfc1850a4de5807004a2e Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 14 Jul 2011 13:44:56 -0400 Subject: Update the agent plugin so that it gets 'b64_contents' from the args dict instead of 'b64_file' (which isn't what nova sends). --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index b8a1b936a..68d7e7bff 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -127,7 +127,7 @@ def inject_file(self, arg_dict): been disabled, and raise a NotImplemented error if that is the case. """ b64_path = arg_dict["b64_path"] - b64_file = arg_dict["b64_file"] + b64_file = arg_dict["b64_contents"] request_id = arg_dict["id"] if self._agent_has_method("file_inject"): # New version of the agent. Agent should receive a 'value' -- cgit From 58eb29ebe4376a276a54f4fd984802a0e50fb8e3 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Fri, 15 Jul 2011 15:05:46 -0400 Subject: Updates to the XenServer agent plugin to fix file injection: -Update _agent_has_method so that it parses the features 'message' from nova-agent correctly. (it was trying to call .split on a dict). -Rip out the agent_has_method caching functionality which just plain isn't working with XenServer 5.6 SP2. -Pass the arg_dict to _agent_has_method. This fixes an issue where a subsequent call to xenstore.write_record didn't get the 'dom_id' (KeyError). -Fix a string formatting issue in inject_file in creating the b64 data. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 44 ++++++++++------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 68d7e7bff..b169a74bf 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -37,7 +37,7 @@ import time import XenAPIPlugin from pluginlib_nova import * -configure_logging("xenstore") +configure_logging("agent") import xenstore AGENT_TIMEOUT = 30 @@ -129,18 +129,18 @@ def inject_file(self, arg_dict): b64_path = arg_dict["b64_path"] b64_file = arg_dict["b64_contents"] request_id = arg_dict["id"] - if self._agent_has_method("file_inject"): + if _agent_has_method(self, "file_inject", arg_dict): # 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"): + elif _agent_has_method(self, "injectfile", arg_dict): # 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) + new_b64 = base64.b64encode("%s,%s" % (raw_path, raw_file)) arg_dict["value"] = json.dumps({"name": "injectfile", "value": new_b64}) else: @@ -174,30 +174,24 @@ def agent_update(self, arg_dict): return resp -def _agent_has_method(self, method): +def _agent_has_method(self, method, arg_dict): """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. + features. """ + tmp_id = commands.getoutput("uuidgen") + dct = {} + dct.update(arg_dict) + dct["value"] = json.dumps({"name": "features", "value": ""}) + dct["path"] = "data/host/%s" % tmp_id + xenstore.write_record(self, dct) 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 + resp = _wait_for_agent(self, tmp_id, dct) + except TimeoutError, e: + raise PluginError(e) + response = json.loads(resp) + method_arr = response["message"].split(",") + # The agent returns a comma-separated list of methods in the message + return method in method_arr def _wait_for_agent(self, request_id, arg_dict): -- cgit From 3233d6cafb22305f09c1384ba30e677751cace6a Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Sat, 16 Jul 2011 23:30:47 -0400 Subject: Change _agent_has_method to _get_agent_features. Update the inject files function so that it calls _get_agent_features only once per injected file. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index b169a74bf..1321c820e 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -129,13 +129,14 @@ def inject_file(self, arg_dict): b64_path = arg_dict["b64_path"] b64_file = arg_dict["b64_contents"] request_id = arg_dict["id"] - if _agent_has_method(self, "file_inject", arg_dict): + agent_features = _get_agent_features(self, arg_dict) + if "file_inject" in agent_features: # 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 _agent_has_method(self, "injectfile", arg_dict): + elif "injectfile" in agent_features: # Old agent requires file path and file contents to be # combined into one base64 value. raw_path = base64.b64decode(b64_path) @@ -174,10 +175,8 @@ def agent_update(self, arg_dict): return resp -def _agent_has_method(self, method, arg_dict): - """Check that the agent has a particular method by checking its - features. - """ +def _get_agent_features(self, arg_dict): + """Return an array of features that an agent supports.""" tmp_id = commands.getoutput("uuidgen") dct = {} dct.update(arg_dict) @@ -189,9 +188,7 @@ def _agent_has_method(self, method, arg_dict): except TimeoutError, e: raise PluginError(e) response = json.loads(resp) - method_arr = response["message"].split(",") - # The agent returns a comma-separated list of methods in the message - return method in method_arr + return response["message"].split(",") def _wait_for_agent(self, request_id, arg_dict): -- cgit From b927674112849e7b4ebbd59c188d8f7a1eb47e2a Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 18 Jul 2011 09:38:50 -0400 Subject: Check returncode in get_agent_features. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 1321c820e..41225e6f3 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -188,7 +188,10 @@ def _get_agent_features(self, arg_dict): except TimeoutError, e: raise PluginError(e) response = json.loads(resp) - return response["message"].split(",") + if response['returncode'] != '0': + return response["message"].split(",") + else: + return {} def _wait_for_agent(self, request_id, arg_dict): -- cgit From cf14d867673e944cc0c0d5fc160d2fbcfe56e98e Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 18 Jul 2011 10:29:49 -0400 Subject: returncode is an integer. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 41225e6f3..8ec4fb061 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -188,7 +188,7 @@ def _get_agent_features(self, arg_dict): except TimeoutError, e: raise PluginError(e) response = json.loads(resp) - if response['returncode'] != '0': + if response['returncode'] != 0: return response["message"].split(",") else: return {} -- cgit From 813253e8bea9a8db9c1df45f9aa5e094503a015a Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 18 Jul 2011 13:18:16 -0400 Subject: Don't jsonify the inject_file response. It is already json. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 1 - 1 file changed, 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index 8ec4fb061..288ccc78a 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -114,7 +114,6 @@ 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 -- cgit From 686cd2c5b50b1a50bd3c942b8dde960b7b5fb5d8 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 20 Jul 2011 14:08:38 +0000 Subject: Some older windows agents will crash if the public key for the keyinit command is not a string. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/agent | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent index b8a1b936a..6c6b0930f 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent @@ -72,7 +72,9 @@ def key_init(self, arg_dict): info to be passed, such as passwords. Returns the shared secret key value. """ - pub = int(arg_dict["pub"]) + # WARNING: Some older Windows agents will crash if the public key isn't + # a string + pub = arg_dict["pub"] arg_dict["value"] = json.dumps({"name": "keyinit", "value": pub}) request_id = arg_dict["id"] arg_dict["path"] = "data/host/%s" % request_id -- cgit From 6a88f87c11472484f35e1116f107410c031b6838 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 20 Jul 2011 15:16:36 +0000 Subject: Fix permissions for plugins --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/migration | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py | 0 plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/glance mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/migration mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore mode change 100755 => 100644 plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py mode change 100644 => 100755 plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration b/plugins/xenserver/xenapi/etc/xapi.d/plugins/migration old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore b/plugins/xenserver/xenapi/etc/xapi.d/plugins/objectstore old mode 100644 new mode 100755 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/pluginlib_nova.py old mode 100755 new mode 100644 diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost b/plugins/xenserver/xenapi/etc/xapi.d/plugins/xenhost old mode 100644 new mode 100755 -- cgit From 4def65d37886fff0dc9f238bca5454abaacb6f76 Mon Sep 17 00:00:00 2001 From: "Kevin L. Mitchell" Date: Wed, 27 Jul 2011 18:13:04 +0000 Subject: Use auth_token to set x-auth-token header in glance requests --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index fbe080b22..86e837849 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -67,12 +67,17 @@ def _copy_kernel_vdi(dest, copy_args): def _download_tarball(sr_path, staging_path, image_id, glance_host, - glance_port): + glance_port, auth_token): """Download the tarball image from Glance and extract it into the staging area. """ + # Build request headers + headers = {} + if auth_token: + headers['x-auth-token'] = auth_token + conn = httplib.HTTPConnection(glance_host, glance_port) - conn.request('GET', '/v1/images/%s' % image_id) + conn.request('GET', '/v1/images/%s' % image_id, headers=headers) resp = conn.getresponse() if resp.status == httplib.NOT_FOUND: raise Exception("Image '%s' not found in Glance" % image_id) @@ -236,7 +241,8 @@ def _prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids): os.link(source, link_name) -def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type): +def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, + auth_token): """ Create a tarball of the image and then stream that into Glance using chunked-transfer-encoded HTTP. @@ -263,6 +269,10 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type): 'x-image-meta-container-format': 'ovf', 'x-image-meta-property-os-type': os_type} + # If we have an auth_token, set an x-auth-token header + if auth_token: + headers['x-auth-token'] = auth_token + for header, value in headers.iteritems(): conn.putheader(header, value) conn.endheaders() @@ -364,11 +374,12 @@ def download_vhd(session, args): glance_port = params["glance_port"] uuid_stack = params["uuid_stack"] sr_path = params["sr_path"] + auth_token = params["auth_token"] staging_path = _make_staging_area(sr_path) try: _download_tarball(sr_path, staging_path, image_id, glance_host, - glance_port) + glance_port, auth_token) # Right now, it's easier to return a single string via XenAPI, # so we'll json encode the list of VHDs. return json.dumps(_import_vhds(sr_path, staging_path, uuid_stack)) @@ -386,12 +397,13 @@ def upload_vhd(session, args): glance_port = params["glance_port"] sr_path = params["sr_path"] os_type = params["os_type"] + auth_token = params["auth_token"] staging_path = _make_staging_area(sr_path) try: _prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids) _upload_tarball(staging_path, image_id, glance_host, glance_port, - os_type) + os_type, auth_token) finally: _cleanup_staging_area(staging_path) -- cgit From 5e1d63cf3b16f78f02e9c2642f60a43402a933a9 Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Thu, 4 Aug 2011 10:41:42 -0400 Subject: Updates to the XenServer glance plugin so that it obtains the set of existing headers and sends them along with the request to PUT a snapshotted image into glance. --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 86e837849..17a5dbbfb 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -248,6 +248,19 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, using chunked-transfer-encoded HTTP. """ conn = httplib.HTTPConnection(glance_host, glance_port) + + # NOTE(dprince): We need to resend any existing Glance meta/property + # headers so they are preserved in Glance. We obtain them here with a + # HEAD request. + conn.request('HEAD', '/v1/images/%s' % image_id) + resp = conn.getresponse() + if resp.status != httplib.OK: + raise Exception("Unexpected response from Glance %i" % resp.status) + headers = {} + for header, value in resp.getheaders(): + if header.lower().startswith("x-image-meta-property-"): + headers[header.lower()] = value + # NOTE(sirp): httplib under python2.4 won't accept a file-like object # to request conn.putrequest('PUT', '/v1/images/%s' % image_id) @@ -260,7 +273,7 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, # 2. We're currently uploading a vanilla tarball. In order to be OVF/OVA # compliant, we'll need to embed a minimal OVF manifest as the first # file. - headers = { + ovf_headers = { 'content-type': 'application/octet-stream', 'transfer-encoding': 'chunked', 'x-image-meta-is-public': 'True', @@ -271,7 +284,9 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, # If we have an auth_token, set an x-auth-token header if auth_token: - headers['x-auth-token'] = auth_token + ovf_headers['x-auth-token'] = auth_token + + headers.update(ovf_headers) for header, value in headers.iteritems(): conn.putheader(header, value) -- cgit From 66916be1ad5bbc0cdc19928ee35e5e8f4e4a3915 Mon Sep 17 00:00:00 2001 From: Rick Harris Date: Fri, 5 Aug 2011 00:12:19 +0000 Subject: Read response to reset HTTPConnection state machine --- plugins/xenserver/xenapi/etc/xapi.d/plugins/glance | 3 +++ 1 file changed, 3 insertions(+) (limited to 'plugins') diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance index 17a5dbbfb..a06312890 100755 --- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance +++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/glance @@ -261,6 +261,9 @@ def _upload_tarball(staging_path, image_id, glance_host, glance_port, os_type, if header.lower().startswith("x-image-meta-property-"): headers[header.lower()] = value + # Toss body so connection state-machine is ready for next request/response + resp.read() + # NOTE(sirp): httplib under python2.4 won't accept a file-like object # to request conn.putrequest('PUT', '/v1/images/%s' % image_id) -- cgit