diff options
| author | Soren Hansen <soren@linux2go.dk> | 2011-02-19 00:37:15 +0100 |
|---|---|---|
| committer | Soren Hansen <soren@linux2go.dk> | 2011-02-19 00:37:15 +0100 |
| commit | c10e3ddb19f20e5ac3a424a2296fe63fa4c4b7ee (patch) | |
| tree | d6553216bc3b3988a1c80b53d37e93e1b9a94992 /nova/virt | |
| parent | 23729c543350ce4ce563077522f18d0bedd1e61b (diff) | |
| parent | 8de8d1d045ca9fe12596e53d2244f4f8703cc209 (diff) | |
Merge trunk
Diffstat (limited to 'nova/virt')
| -rw-r--r-- | nova/virt/fake.py | 15 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 50 | ||||
| -rw-r--r-- | nova/virt/xenapi_conn.py | 6 |
3 files changed, 71 insertions, 0 deletions
diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 161445b86..92749f38a 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -152,6 +152,21 @@ class FakeConnection(object): """ pass + def inject_file(self, instance, b64_path, b64_contents): + """ + Writes a file on the specified instance. + + The first parameter is an instance of nova.compute.service.Instance, + and so the instance is being specified as instance.name. The second + parameter is the base64-encoded path to which the file is to be + written on the instance; the third is the contents of the file, also + base64-encoded. + + The work will be done asynchronously. This function returns a + task that allows the caller to detect when it is complete. + """ + pass + def rescue(self, instance): """ Rescue the specified instance. diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 842e08f22..0168681f6 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -79,6 +79,7 @@ class VMOps(object): user = AuthManager().get_user(instance.user_id) project = AuthManager().get_project(instance.project_id) + #if kernel is not present we must download a raw disk if instance.kernel_id: disk_image_type = ImageType.DISK @@ -150,6 +151,21 @@ class VMOps(object): LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.') % locals()) + def _inject_onset_files(): + onset_files = instance.onset_files + if onset_files: + # Check if this is a JSON-encoded string and convert if needed. + if isinstance(onset_files, basestring): + try: + onset_files = json.loads(onset_files) + except ValueError: + LOG.exception(_("Invalid value for onset_files: '%s'") + % onset_files) + onset_files = [] + # Inject any files, if specified + for path, contents in instance.onset_files: + LOG.debug(_("Injecting file path: '%s'") % path) + self.inject_file(instance, path, contents) # NOTE(armando): Do we really need to do this in virt? # NOTE(tr3buchet): not sure but wherever we do it, we need to call # reset_network afterwards @@ -163,6 +179,8 @@ class VMOps(object): if state == power_state.RUNNING: LOG.debug(_('Instance %s: booted'), instance['name']) timer.stop() + _inject_onset_files() + return True except Exception, exc: LOG.warn(exc) LOG.exception(_('instance %s: failed to boot'), @@ -171,6 +189,7 @@ class VMOps(object): instance['id'], power_state.SHUTDOWN) timer.stop() + return False timer.f = _wait_for_boot @@ -304,6 +323,32 @@ class VMOps(object): raise RuntimeError(resp_dict['message']) return resp_dict['message'] + def inject_file(self, instance, b64_path, b64_contents): + """Write a file to the VM instance. The path to which it is to be + written and the contents of the file need to be supplied; both should + be base64-encoded to prevent errors with non-ASCII characters being + transmitted. If the agent does not support file injection, or the user + has disabled it, a NotImplementedError will be raised. + """ + # Files/paths *should* be base64-encoded at this point, but + # double-check to make sure. + b64_path = utils.ensure_b64_encoding(b64_path) + b64_contents = utils.ensure_b64_encoding(b64_contents) + + # Need to uniquely identify this request. + transaction_id = str(uuid.uuid4()) + args = {'id': transaction_id, 'b64_path': b64_path, + 'b64_contents': b64_contents} + # If the agent doesn't support file injection, a NotImplementedError + # will be raised with the appropriate message. + resp = self._make_agent_call('inject_file', instance, '', args) + resp_dict = json.loads(resp) + if resp_dict['returncode'] != '0': + # There was some other sort of error; the message will contain + # a description of the error. + raise RuntimeError(resp_dict['message']) + return resp_dict['message'] + def _shutdown(self, instance, vm): """Shutdown an instance """ state = self.get_info(instance['name'])['state'] @@ -515,6 +560,11 @@ class VMOps(object): if 'TIMEOUT:' in err_msg: LOG.error(_('TIMEOUT: The call to %(method)s timed out. ' 'VM id=%(instance_id)s; args=%(strargs)s') % locals()) + elif 'NOT IMPLEMENTED:' in err_msg: + LOG.error(_('NOT IMPLEMENTED: The call to %(method)s is not' + ' supported by the agent. VM id=%(instance_id)s;' + ' args=%(strargs)s') % locals()) + raise NotImplementedError(err_msg) else: LOG.error(_('The call to %(method)s returned an error: %(e)s. ' 'VM id=%(instance_id)s; args=%(strargs)s') % locals()) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 2720d175f..c2f65699f 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -168,6 +168,12 @@ class XenAPIConnection(object): """Set the root/admin password on the VM instance""" self._vmops.set_admin_password(instance, new_pass) + def inject_file(self, instance, b64_path, b64_contents): + """Create a file on the VM instance. The file path and contents + should be base64-encoded. + """ + self._vmops.inject_file(instance, b64_path, b64_contents) + def destroy(self, instance): """Destroy VM instance""" self._vmops.destroy(instance) |
