summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorRick Harris <rick.harris@rackspace.com>2011-01-17 11:16:36 -0600
committerRick Harris <rick.harris@rackspace.com>2011-01-17 11:16:36 -0600
commitb5445da21b9ae91308e2adecc7aaa8e56e278d50 (patch)
tree43c7d4de0830230da714888d91e7f1142e62d3d2 /plugins
parent0d6882fb2a3ec3b45b28120d00b8b4ff5fbc9187 (diff)
parent825652456ac826a2108956ba8a9cbdc8221520dc (diff)
downloadnova-b5445da21b9ae91308e2adecc7aaa8e56e278d50.tar.gz
nova-b5445da21b9ae91308e2adecc7aaa8e56e278d50.tar.xz
nova-b5445da21b9ae91308e2adecc7aaa8e56e278d50.zip
Merging trunk
Diffstat (limited to 'plugins')
-rwxr-xr-xplugins/xenserver/xenapi/etc/xapi.d/plugins/agent126
1 files changed, 126 insertions, 0 deletions
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
new file mode 100755
index 000000000..12c3a19c8
--- /dev/null
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
@@ -0,0 +1,126 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack LLC.
+# Copyright 2011 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+#
+# XenAPI plugin for reading/writing information to xenstore
+#
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+import os
+import random
+import subprocess
+import tempfile
+import time
+
+import XenAPIPlugin
+
+from pluginlib_nova import *
+configure_logging("xenstore")
+import xenstore
+
+AGENT_TIMEOUT = 30
+
+
+def jsonify(fnc):
+ def wrapper(*args, **kwargs):
+ return json.dumps(fnc(*args, **kwargs))
+ return wrapper
+
+
+class TimeoutError(StandardError):
+ pass
+
+
+@jsonify
+def key_init(self, arg_dict):
+ """Handles the Diffie-Hellman key exchange with the agent to
+ establish the shared secret key used to encrypt/decrypt sensitive
+ info to be passed, such as passwords. Returns the shared
+ secret key value.
+ """
+ pub = int(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
+ 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
+
+
+@jsonify
+def password(self, arg_dict):
+ """Writes a request to xenstore that tells the agent to set
+ the root password for the given VM. The password should be
+ encrypted using the shared secret key that was returned by a
+ previous call to key_init. The encrypted password value should
+ be passed as the value for the 'enc_pass' key in arg_dict.
+ """
+ pub = int(arg_dict["pub"])
+ enc_pass = arg_dict["enc_pass"]
+ arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass})
+ request_id = arg_dict["id"]
+ 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 _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
+ the agent's response for that request will be in 'data/guest/{id}'.
+ If no value appears from the agent within the time specified by
+ AGENT_TIMEOUT, the original request is deleted and a TimeoutError
+ is returned.
+ """
+ arg_dict["path"] = "data/guest/%s" % request_id
+ arg_dict["ignore_missing_path"] = True
+ start = time.time()
+ while True:
+ if time.time() - start > AGENT_TIMEOUT:
+ # No response within the timeout period; bail out
+ # 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)
+ ret = xenstore.read_record(self, arg_dict)
+ # Note: the response for None with be a string that includes
+ # double quotes.
+ if ret != '"None"':
+ # The agent responded
+ return ret
+ else:
+ time.sleep(3)
+
+
+if __name__ == "__main__":
+ XenAPIPlugin.dispatch(
+ {"key_init": key_init,
+ "password": password})