diff options
author | Ed Leafe <ed@leafe.com> | 2011-01-06 15:53:11 -0600 |
---|---|---|
committer | Ed Leafe <ed@leafe.com> | 2011-01-06 15:53:11 -0600 |
commit | e66f3017373dcf9135c53ae4d510b0b2a5dcecf0 (patch) | |
tree | 33e07b321be994a9231e23603a6039518aacf625 | |
parent | ed6a4974f19ab7b13c90d41b83ae279403e272e8 (diff) | |
download | nova-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.py | 17 | ||||
-rw-r--r-- | nova/compute/manager.py | 3 | ||||
-rw-r--r-- | nova/exception.py | 4 | ||||
-rw-r--r-- | nova/virt/xenapi/vmops.py | 22 | ||||
-rw-r--r-- | nova/virt/xenapi_conn.py | 16 | ||||
-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: |