summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Leafe <ed@leafe.com>2011-01-06 15:53:11 -0600
committerEd Leafe <ed@leafe.com>2011-01-06 15:53:11 -0600
commite66f3017373dcf9135c53ae4d510b0b2a5dcecf0 (patch)
tree33e07b321be994a9231e23603a6039518aacf625
parented6a4974f19ab7b13c90d41b83ae279403e272e8 (diff)
downloadnova-e66f3017373dcf9135c53ae4d510b0b2a5dcecf0.tar.gz
nova-e66f3017373dcf9135c53ae4d510b0b2a5dcecf0.tar.xz
nova-e66f3017373dcf9135c53ae4d510b0b2a5dcecf0.zip
Got the basic 'set admin password' stuff working
-rw-r--r--nova/api/openstack/servers.py17
-rw-r--r--nova/compute/manager.py3
-rw-r--r--nova/exception.py4
-rw-r--r--nova/virt/xenapi/vmops.py22
-rw-r--r--nova/virt/xenapi_conn.py16
-rwxr-xr-x[-rw-r--r--]plugins/xenserver/xenapi/etc/xapi.d/plugins/agent (renamed from plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py)22
6 files changed, 41 insertions, 43 deletions
diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py
index e0513e4c1..bc89f696c 100644
--- a/nova/api/openstack/servers.py
+++ b/nova/api/openstack/servers.py
@@ -104,7 +104,8 @@ class Controller(wsgi.Controller):
def show(self, req, id):
""" Returns server details by server id """
try:
- instance = self.compute_api.get_instance(req.environ['nova.context'], id)
+ instance = self.compute_api.get_instance(
+ req.environ['nova.context'], id)
return _translate_detail_keys(instance)
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
@@ -141,6 +142,7 @@ class Controller(wsgi.Controller):
if not inst_dict:
return faults.Fault(exc.HTTPUnprocessableEntity())
+ ctxt = req.environ['nova.context']
update_dict = {}
func = None
if 'adminPass' in inst_dict['server']:
@@ -148,21 +150,18 @@ class Controller(wsgi.Controller):
func = self.compute_api.set_admin_password
if 'name' in inst_dict['server']:
update_dict['display_name'] = inst_dict['server']['name']
-
+ if func:
+ try:
+ func(ctxt, id)
+ except exception.TimeoutException, e:
+ return exc.HTTPRequestTimeout()
try:
- ctxt = req.environ['nova.context']
# The ID passed in is actually the internal_id of the
# instance, not the value of the id column in the DB.
instance = self.compute_api.get_instance(ctxt, id)
self.compute_api.update(ctxt, instance.id, **update_dict)
except exception.NotFound:
return faults.Fault(exc.HTTPNotFound())
-
- logging.error("ZZZZ func=%s" % func)
- logging.error("ZZZZ UPD=%s" % id)
-
- if func:
- func(ctxt, id)
return exc.HTTPNoContent()
def action(self, req, id):
diff --git a/nova/compute/manager.py b/nova/compute/manager.py
index 201fffc68..52acfebea 100644
--- a/nova/compute/manager.py
+++ b/nova/compute/manager.py
@@ -83,7 +83,6 @@ class ComputeManager(manager.Manager):
# FIXME(ja): include other fields from state?
instance_ref = self.db.instance_get(context, instance_id)
try:
- #info = self.driver.get_info(instance_ref['name'])
info = self.driver.get_info(instance_ref)
state = info['state']
except exception.NotFound:
@@ -266,8 +265,6 @@ class ComputeManager(manager.Manager):
logging.debug('instance %s: setting admin password',
instance_ref['name'])
- self.db.instance_set_state(context, instance_id,
- power_state.NOSTATE, 'setting_password')
if new_pass is None:
# Generate a random password
new_pass = self._generate_password(FLAGS.password_length)
diff --git a/nova/exception.py b/nova/exception.py
index 277033e0f..52bf2a2a7 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -77,6 +77,10 @@ class InvalidInputException(Error):
pass
+class TimeoutException(Error):
+ pass
+
+
def wrap_exception(f):
def _wrap(*args, **kw):
try:
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index e092601b9..5f1654a49 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -130,21 +130,17 @@ class VMOps(object):
"""Refactored out the common code of many methods that receive either
a vm name or a vm instance, and want a vm instance in return.
"""
- logging.error("ZZZZ opaq instance_or_vm=%s" % instance_or_vm)
vm = None
try:
if instance_or_vm.startswith("OpaqueRef:"):
- logging.error("ZZZZ opaq startswith")
# Got passed an opaque ref; return it
return instance_or_vm
else:
# Must be the instance name
- logging.error("ZZZZ opaq inst name")
instance_name = instance_or_vm
except AttributeError:
# Not a string; must be a vm instance
instance_name = instance_or_vm.name
- logging.error("ZZZZ opaq instance, name=%s" % instance_name)
vm = VMHelper.lookup(self._session, instance_name)
if vm is None:
raise Exception(_('Instance not present %s') % instance_name)
@@ -210,9 +206,6 @@ class VMOps(object):
simple Diffie-Hellman class instead of the more advanced one in
M2Crypto for compatibility with the agent code.
"""
-
- logging.error("ZZZZ SET PASS CALLED")
-
# Need to uniquely identify this request.
transaction_id = str(uuid.uuid4())
# The simple Diffie-Hellman class is used to manage key exchange.
@@ -306,9 +299,6 @@ class VMOps(object):
def get_info(self, instance):
"""Return data about VM instance"""
-
- logging.error("ZZZZ get_info instance=%s" % instance)
-
vm = self._get_vm_opaque_ref(instance)
rec = self._session.get_xenapi().VM.get_record(vm)
return VMHelper.compile_info(rec)
@@ -370,13 +360,14 @@ class VMOps(object):
def _make_agent_call(self, method, vm, path, addl_args={}):
"""Abstracts out the interaction with the agent xenapi plugin."""
- return self._make_plugin_call('agent.py', method=method, vm=vm,
+ return self._make_plugin_call('agent', method=method, vm=vm,
path=path, addl_args=addl_args)
def _make_plugin_call(self, plugin, method, vm, path, addl_args={}):
"""Abstracts out the process of calling a method of a xenapi plugin.
Any errors raised by the plugin will in turn raise a RuntimeError here.
"""
+ instance_id = vm.id
vm = self._get_vm_opaque_ref(vm)
rec = self._session.get_xenapi().VM.get_record(vm)
args = {'dom_id': rec['domid'], 'path': path}
@@ -386,9 +377,14 @@ class VMOps(object):
args['testing_mode'] = 'true'
try:
task = self._session.async_call_plugin(plugin, method, args)
- ret = self._session.wait_for_task(0, task)
+ ret = self._session.wait_for_task(instance_id, task)
except self.XenAPI.Failure, e:
- raise RuntimeError("%s" % e.details[-1])
+ err_trace = e.details[-1]
+ err_msg = err_trace.splitlines()[-1]
+ if 'TIMEOUT:' in err_msg:
+ raise exception.TimeoutException(err_msg)
+ else:
+ raise RuntimeError("%s" % e.details[-1])
return ret
def add_to_xenstore(self, vm, path, key, value):
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 0ceac8c97..c9428e3a6 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -170,9 +170,6 @@ class XenAPIConnection(object):
def get_info(self, instance_id):
"""Return data about VM instance"""
-
- logging.error("ZZZZ conn get_info id=%s" % instance_id)
-
return self._vmops.get_info(instance_id)
def get_diagnostics(self, instance):
@@ -251,7 +248,8 @@ class XenAPISession(object):
def _poll_task(self, id, task, done):
"""Poll the given XenAPI task, and fire the given action if we
- get a result."""
+ get a result.
+ """
try:
name = self._session.xenapi.task.get_name_label(task)
status = self._session.xenapi.task.get_status(task)
@@ -278,16 +276,6 @@ class XenAPISession(object):
error_info))
done.send_exception(self.XenAPI.Failure(error_info))
db.instance_action_create(context.get_admin_context(), action)
-# import sqlalchemy
-# from sqlalchemy.exc import IntegrityError as IntegrityError
-# try:
-# db.instance_action_create(context.get_admin_context(), action)
-# except IntegrityError:
-# # Some methods don't pass unique IDs, so the call to
-# # instance_action_create() will raise IntegrityErrors. Rather
-# # than bomb out, I'm explicitly silencing them so that the
-# # code can continue to work until they fix that method.
-# pass
except self.XenAPI.Failure, exc:
logging.warn(exc)
diff --git a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
index 4b072ce67..244509f3f 100644..100755
--- a/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent.py
+++ b/plugins/xenserver/xenapi/etc/xapi.d/plugins/agent
@@ -42,9 +42,16 @@ AGENT_TIMEOUT = 30
PRETEND_SECRET = 11111
+def jsonify(fnc):
+ def wrapper(*args, **kwargs):
+ return json.dumps(fnc(*args, **kwargs))
+ return wrapper
+
+
class TimeoutError(StandardError):
pass
+
class SimpleDH(object):
"""This class wraps all the functionality needed to implement
basic Diffie-Hellman-Merkle key exchange in Python. It features
@@ -138,6 +145,8 @@ def _run_command(cmd):
raise PluginError(err)
return proc.stdout.read()
+
+@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
@@ -152,7 +161,7 @@ def key_init(self, arg_dict):
pretend = SimpleDH(secret=PRETEND_SECRET)
shared = pretend.compute_shared(pub)
# Simulate the agent's response
- ret = '{ "returncode": "D0", "message": "%s", "shared": "%s" }' % (pretend.get_public(), shared)
+ ret = {"returncode": "D0", "message": "%s", "shared": "%s"} % (pretend.get_public(), shared)
return ret
arg_dict["path"] = "data/host/%s" % request_id
xenstore.write_record(self, arg_dict)
@@ -162,6 +171,8 @@ def key_init(self, arg_dict):
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
@@ -176,7 +187,7 @@ def password(self, arg_dict):
pretend = SimpleDH(secret=PRETEND_SECRET)
pretend.compute_shared(pub)
pw = pretend.decrypt(enc_pass)
- ret = '{ "returncode": "0", "message": "%s" }' % pw
+ ret = {"returncode": "0", "message": "%s"} % pw
return ret
arg_dict["value"] = json.dumps({"name": "password", "value": enc_pass})
request_id = arg_dict["id"]
@@ -188,6 +199,7 @@ def password(self, arg_dict):
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
@@ -205,10 +217,12 @@ 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("No response from agent within %s seconds." %
+ raise TimeoutError("TIMEOUT: No response from agent within %s seconds." %
AGENT_TIMEOUT)
ret = xenstore.read_record(self, arg_dict)
- if ret != "None":
+ # Note: the response for None with be a string that includes
+ # double quotes.
+ if ret != '"None"':
# The agent responded
return ret
else: