Example #1
0
 def __init__(self, url, user, pw):
     super(XenAPIConnection, self).__init__()
     self._session = XenAPISession(url, user, pw)
     self._volumeops = VolumeOps(self._session)
     self._host_state = None
     self._product_version = self._session.get_product_version()
     self._vmops = VMOps(self._session, self._product_version)
Example #2
0
    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None
        self._host = host.Host(self._session)
        self._product_version = self._session.get_product_version()
        self._vmops = VMOps(self._session, self._product_version)
        self._initiator = None
        self._pool = pool.ResourcePool(self._session)

        self._capture_dom0_hostname()
Example #3
0
 def __init__(self, url, user, pw):
     super(XenAPIConnection, self).__init__()
     self._session = XenAPISession(url, user, pw)
     self._volumeops = VolumeOps(self._session)
     self._host_state = None
     self._product_version = self._session.get_product_version()
     self._vmops = VMOps(self._session, self._product_version)
Example #4
0
    def __init__(self, *args, **kwargs):
        """Connect to the hypervisor."""

        # This driver leverages Xen storage manager, and hence requires
        # hypervisor to be Xen
        if FLAGS.connection_type != 'xenapi':
            raise exception.Error(_('XenSMDriver requires xenapi connection'))

        url = FLAGS.xenapi_connection_url
        username = FLAGS.xenapi_connection_username
        password = FLAGS.xenapi_connection_password
        try:
            session = XenAPISession(url, username, password)
            self._volumeops = VolumeOps(session)
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to initiate session"))

        super(XenSMDriver, self).__init__(execute=utils.execute,
                                          sync_exec=utils.execute,
                                          *args, **kwargs)
Example #5
0
    def __init__(self, *args, **kwargs):
        """Connect to the hypervisor."""

        # This driver leverages Xen storage manager, and hence requires
        # hypervisor to be Xen
        if FLAGS.connection_type != 'xenapi':
            raise exception.Error(_('XenSMDriver requires xenapi connection'))

        url = FLAGS.xenapi_connection_url
        username = FLAGS.xenapi_connection_username
        password = FLAGS.xenapi_connection_password
        try:
            session = XenAPISession(url, username, password)
            self._volumeops = VolumeOps(session)
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to initiate session"))

        super(XenSMDriver, self).__init__(execute=utils.execute,
                                          sync_exec=utils.execute,
                                          *args, **kwargs)
Example #6
0
class XenAPIConnection(driver.ComputeDriver):
    """A connection to XenServer or Xen Cloud Platform"""
    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None
        self._product_version = self._session.get_product_version()
        self._vmops = VMOps(self._session, self._product_version)

    @property
    def host_state(self):
        if not self._host_state:
            self._host_state = HostState(self._session)
        return self._host_state

    def init_host(self, host):
        #FIXME(armando): implement this
        #NOTE(armando): would we need a method
        #to call when shutting down the host?
        #e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def list_instances_detail(self):
        return self._vmops.list_instances_detail()

    def spawn(self,
              context,
              instance,
              image_meta,
              network_info=None,
              block_device_info=None):
        """Create VM instance"""
        self._vmops.spawn(context, instance, image_meta, network_info)

    def confirm_migration(self, migration, instance, network_info):
        """Confirms a resize, destroying the source VM"""
        # TODO(Vek): Need to pass context in for access to auth_token
        self._vmops.confirm_migration(migration, instance, network_info)

    def finish_revert_migration(self, instance):
        """Finish reverting a resize, powering back on the instance"""
        self._vmops.finish_revert_migration(instance)

    def finish_migration(self,
                         context,
                         migration,
                         instance,
                         disk_info,
                         network_info,
                         image_meta,
                         resize_instance=False):
        """Completes a resize, turning on the migrated instance"""
        self._vmops.finish_migration(context, migration, instance, disk_info,
                                     network_info, image_meta, resize_instance)

    def snapshot(self, context, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(context, instance, image_id)

    def reboot(self, instance, network_info, reboot_type):
        """Reboot VM instance"""
        self._vmops.reboot(instance, reboot_type)

    def set_admin_password(self, instance, new_pass):
        """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, network_info, block_device_info=None):
        """Destroy VM instance"""
        self._vmops.destroy(instance, network_info)

    def pause(self, instance):
        """Pause VM instance"""
        self._vmops.pause(instance)

    def unpause(self, instance):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance)

    def migrate_disk_and_power_off(self, context, instance, dest,
                                   instance_type):
        """Transfers the VHD of a running instance to another host, then shuts
        off the instance copies over the COW disk"""
        return self._vmops.migrate_disk_and_power_off(context, instance, dest,
                                                      instance_type)

    def suspend(self, instance):
        """suspend the specified instance"""
        self._vmops.suspend(instance)

    def resume(self, instance):
        """resume the specified instance"""
        self._vmops.resume(instance)

    def rescue(self, context, instance, network_info, image_meta):
        """Rescue the specified instance"""
        self._vmops.rescue(context, instance, network_info, image_meta)

    def unrescue(self, instance, network_info):
        """Unrescue the specified instance"""
        self._vmops.unrescue(instance)

    def power_off(self, instance):
        """Power off the specified instance"""
        self._vmops.power_off(instance)

    def power_on(self, instance):
        """Power on the specified instance"""
        self._vmops.power_on(instance)

    def poll_rebooting_instances(self, timeout):
        """Poll for rebooting instances"""
        self._vmops.poll_rebooting_instances(timeout)

    def poll_rescued_instances(self, timeout):
        """Poll for rescued instances"""
        self._vmops.poll_rescued_instances(timeout)

    def poll_unconfirmed_resizes(self, resize_confirm_window):
        """Poll for unconfirmed resizes"""
        self._vmops.poll_unconfirmed_resizes(resize_confirm_window)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def inject_network_info(self, instance, network_info):
        """inject network info for specified instance"""
        self._vmops.inject_network_info(instance, network_info)

    def plug_vifs(self, instance_ref, network_info):
        """Plug VIFs into networks."""
        self._vmops.plug_vifs(instance_ref, network_info)

    def unplug_vifs(self, instance_ref, network_info):
        """Unplug VIFs from networks."""
        self._vmops.unplug_vifs(instance_ref, network_info)

    def get_info(self, instance_name):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_name)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_all_bw_usage(self, start_time, stop_time=None):
        """Return bandwidth usage info for each interface on each
           running VM"""
        bwusage = []
        start_time = time.mktime(start_time.timetuple())
        if stop_time:
            stop_time = time.mktime(stop_time.timetuple())
        for iusage in self._vmops.get_all_bw_usage(start_time, stop_time).\
                      values():
            for macaddr, usage in iusage.iteritems():
                vi = db.virtual_interface_get_by_address(
                    context.get_admin_context(), macaddr)
                if vi:
                    bwusage.append(
                        dict(virtual_interface=vi,
                             bw_in=usage['bw_in'],
                             bw_out=usage['bw_out']))
        return bwusage

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def get_vnc_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_vnc_console(instance)

    @staticmethod
    def get_host_ip_addr():
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return xs_url.netloc

    def attach_volume(self, connection_info, instance_name, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(connection_info, instance_name,
                                             mountpoint)

    def detach_volume(self, connection_info, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(connection_info, instance_name,
                                             mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return {
            'address': xs_url.netloc,
            'username': FLAGS.xenapi_connection_username,
            'password': FLAGS.xenapi_connection_password
        }

    def update_available_resource(self, ctxt, host):
        """Updates compute manager resource info on ComputeNode table.

        This method is called when nova-compute launches, and
        whenever admin executes "nova-manage service update_resource".

        :param ctxt: security context
        :param host: hostname that compute manager is currently running

        """

        try:
            service_ref = db.service_get_all_compute_by_host(ctxt, host)[0]
        except exception.NotFound:
            raise exception.ComputeServiceUnavailable(host=host)

        host_stats = self.get_host_stats(refresh=True)

        # Updating host information
        total_ram_mb = host_stats['host_memory_total'] / (1024 * 1024)
        free_ram_mb = host_stats['host_memory_free'] / (1024 * 1024)
        total_disk_gb = host_stats['disk_total'] / (1024 * 1024 * 1024)
        used_disk_gb = host_stats['disk_used'] / (1024 * 1024 * 1024)

        dic = {
            'vcpus': 0,
            'memory_mb': total_ram_mb,
            'local_gb': total_disk_gb,
            'vcpus_used': 0,
            'memory_mb_used': total_ram_mb - free_ram_mb,
            'local_gb_used': used_disk_gb,
            'hypervisor_type': 'xen',
            'hypervisor_version': 0,
            'cpu_info': host_stats['host_cpu_info']['cpu_count']
        }

        compute_node_ref = service_ref['compute_node']
        if not compute_node_ref:
            LOG.info(_('Compute_service record created for %s ') % host)
            dic['service_id'] = service_ref['id']
            db.compute_node_create(ctxt, dic)
        else:
            LOG.info(_('Compute_service record updated for %s ') % host)
            db.compute_node_update(ctxt, compute_node_ref[0]['id'], dic)

    def compare_cpu(self, xml):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
        """This method is supported only libvirt."""
        # NOTE(salvatore-orlando): it enforces security groups on
        # host initialization and live migration.
        # Live migration is not supported by XenAPI (as of 2011-11-09)
        # In XenAPI we do not assume instances running upon host initialization
        return

    def live_migration(self,
                       context,
                       instance_ref,
                       dest,
                       post_method,
                       recover_method,
                       block_migration=False):
        """This method is supported only by libvirt."""
        return

    def unfilter_instance(self, instance_ref, network_info):
        """Removes security groups configured for an instance."""
        return self._vmops.unfilter_instance(instance_ref, network_info)

    def refresh_security_group_rules(self, security_group_id):
        """ Updates security group rules for all instances
            associated with a given security group
            Invoked when security group rules are updated
        """
        return self._vmops.refresh_security_group_rules(security_group_id)

    def refresh_security_group_members(self, security_group_id):
        """ Updates security group rules for all instances
            associated with a given security group
            Invoked when instances are added/removed to a security group
        """
        return self._vmops.refresh_security_group_members(security_group_id)

    def update_host_status(self):
        """Update the status info of the host, and return those values
            to the calling program."""
        return self.host_state.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the host. If 'refresh' is
           True, run the update first."""
        return self.host_state.get_host_stats(refresh=refresh)

    def host_power_action(self, host, action):
        """The only valid values for 'action' on XenServer are 'reboot' or
        'shutdown', even though the API also accepts 'startup'. As this is
        not technically possible on XenServer, since the host is the same
        physical machine as the hypervisor, if this is requested, we need to
        raise an exception.
        """
        if action in ("reboot", "shutdown"):
            return self._vmops.host_power_action(host, action)
        else:
            msg = _("Host startup on XenServer is not supported.")
            raise NotImplementedError(msg)

    def set_host_enabled(self, host, enabled):
        """Sets the specified host's ability to accept new instances."""
        return self._vmops.set_host_enabled(host, enabled)
Example #7
0
class XenAPIConnection(driver.ComputeDriver):
    """A connection to XenServer or Xen Cloud Platform"""
    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._vmops = VMOps(self._session)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None

    @property
    def HostState(self):
        if not self._host_state:
            self._host_state = HostState(self._session)
        return self._host_state

    def init_host(self, host):
        #FIXME(armando): implement this
        #NOTE(armando): would we need a method
        #to call when shutting down the host?
        #e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def list_instances_detail(self):
        return self._vmops.list_instances_detail()

    def spawn(self, instance, network_info, block_device_mapping=None):
        """Create VM instance"""
        self._vmops.spawn(instance, network_info)

    def revert_migration(self, instance):
        """Reverts a resize, powering back on the instance"""
        self._vmops.revert_resize(instance)

    def finish_migration(self,
                         instance,
                         disk_info,
                         network_info,
                         resize_instance=False):
        """Completes a resize, turning on the migrated instance"""
        self._vmops.finish_migration(instance, disk_info, network_info,
                                     resize_instance)

    def snapshot(self, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(instance, image_id)

    def reboot(self, instance, network_info):
        """Reboot VM instance"""
        self._vmops.reboot(instance)

    def set_admin_password(self, instance, new_pass):
        """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, network_info):
        """Destroy VM instance"""
        self._vmops.destroy(instance, network_info)

    def pause(self, instance, callback):
        """Pause VM instance"""
        self._vmops.pause(instance, callback)

    def unpause(self, instance, callback):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance, callback)

    def migrate_disk_and_power_off(self, instance, dest):
        """Transfers the VHD of a running instance to another host, then shuts
        off the instance copies over the COW disk"""
        return self._vmops.migrate_disk_and_power_off(instance, dest)

    def suspend(self, instance, callback):
        """suspend the specified instance"""
        self._vmops.suspend(instance, callback)

    def resume(self, instance, callback):
        """resume the specified instance"""
        self._vmops.resume(instance, callback)

    def rescue(self, instance, callback, network_info):
        """Rescue the specified instance"""
        self._vmops.rescue(instance, callback)

    def unrescue(self, instance, callback, network_info):
        """Unrescue the specified instance"""
        self._vmops.unrescue(instance, callback)

    def poll_rescued_instances(self, timeout):
        """Poll for rescued instances"""
        self._vmops.poll_rescued_instances(timeout)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def inject_network_info(self, instance, network_info):
        """inject network info for specified instance"""
        self._vmops.inject_network_info(instance, network_info)

    def plug_vifs(self, instance_ref, network_info):
        self._vmops.plug_vifs(instance_ref, network_info)

    def get_info(self, instance_id):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_id)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def get_host_ip_addr(self):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return xs_url.netloc

    def attach_volume(self, instance_name, device_path, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(instance_name, device_path,
                                             mountpoint)

    def detach_volume(self, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(instance_name, mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return {
            'address': xs_url.netloc,
            'username': FLAGS.xenapi_connection_username,
            'password': FLAGS.xenapi_connection_password
        }

    def update_available_resource(self, ctxt, host):
        """This method is supported only by libvirt."""
        return

    def compare_cpu(self, xml):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def ensure_filtering_rules_for_instance(self, instance_ref):
        """This method is supported only libvirt."""
        return

    def live_migration(self, context, instance_ref, dest, post_method,
                       recover_method):
        """This method is supported only by libvirt."""
        return

    def unfilter_instance(self, instance_ref, network_info):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def update_host_status(self):
        """Update the status info of the host, and return those values
            to the calling program."""
        return self.HostState.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the host. If 'refresh' is
           True, run the update first."""
        return self.HostState.get_host_stats(refresh=refresh)

    def set_host_enabled(self, host, enabled):
        """Sets the specified host's ability to accept new instances."""
        return self._vmops.set_host_enabled(host, enabled)
Example #8
0
class XenSMDriver(VolumeDriver):

    def _convert_config_params(self, conf_str):
        params = dict([item.split("=") for item in conf_str.split()])
        return params

    def _get_introduce_sr_keys(self, params):
        if 'name_label' in params:
            del params['name_label']
        keys = params.keys()
        keys.append('sr_type')
        return keys

    def _create_storage_repo(self, context, backend_ref):
        """Either creates or introduces SR on host
        depending on whether it exists in xapi db."""
        params = self._convert_config_params(backend_ref['config_params'])
        if 'name_label' in params:
            label = params['name_label']
            del params['name_label']
        else:
            label = 'SR-' + str(backend_ref['id'])

        params['sr_type'] = backend_ref['sr_type']

        if backend_ref['sr_uuid'] is None:
            # run the sr create command
            try:
                LOG.debug(_('SR name = %s') % label)
                LOG.debug(_('Params: %s') % str(params))
                sr_uuid = self._volumeops.create_sr(label, params)
            # update sr_uuid and created in db
            except Exception as ex:
                LOG.debug(_("Failed to create sr %s...continuing") \
                          % str(backend_ref['id']))
                raise exception.Error(_('Create failed'))

            LOG.debug(_('SR UUID of new SR is: %s') % sr_uuid)
            try:
                self.db.sm_backend_conf_update(context,
                                               backend_ref['id'],
                                               dict(sr_uuid=sr_uuid))
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_("Failed to update db"))

        else:
            # sr introduce, if not already done
            try:
                self._volumeops.introduce_sr(backend_ref['sr_uuid'], label,
                                              params)
            except Exception as ex:
                LOG.exception(ex)
                LOG.debug(_("Failed to introduce sr %s...continuing") \
                          % str(backend_ref['id']))

    def _create_storage_repos(self, context):
        """Create/Introduce storage repositories at start."""
        backends = self.db.sm_backend_conf_get_all(context)
        for backend in backends:
            try:
                self._create_storage_repo(context, backend)
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_('Failed to reach backend %d') \
                                      % backend['id'])

    def __init__(self, *args, **kwargs):
        """Connect to the hypervisor."""

        # This driver leverages Xen storage manager, and hence requires
        # hypervisor to be Xen
        if FLAGS.connection_type != 'xenapi':
            raise exception.Error(_('XenSMDriver requires xenapi connection'))

        url = FLAGS.xenapi_connection_url
        username = FLAGS.xenapi_connection_username
        password = FLAGS.xenapi_connection_password
        try:
            session = XenAPISession(url, username, password)
            self._volumeops = VolumeOps(session)
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to initiate session"))

        super(XenSMDriver, self).__init__(execute=utils.execute,
                                          sync_exec=utils.execute,
                                          *args, **kwargs)

    def do_setup(self, ctxt):
        """Setup includes creating or introducing storage repos
           existing in the database and destroying deleted ones."""

        # TODO purge storage repos
        self.ctxt = ctxt
        self._create_storage_repos(ctxt)

    def create_volume(self, volume):
        """Creates a logical volume. Can optionally return a Dictionary of
        changes to the volume object to be persisted."""

        # For now the scheduling logic will be to try to fit the volume in
        # the first available backend.
        # TODO better scheduling once APIs are in place
        sm_vol_rec = None
        backends = self.db.sm_backend_conf_get_all(self.ctxt)
        for backend in backends:
            # Ensure that storage repo exists, if not create.
            # This needs to be done because if nova compute and
            # volume are both running on this host, then, as a
            # part of detach_volume, compute could potentially forget SR
            self._create_storage_repo(self.ctxt, backend)
            sm_vol_rec = self._volumeops.\
                              create_volume_for_sm(volume,
                                                   backend['sr_uuid'])
            if sm_vol_rec:
                LOG.debug(_('Volume will be created in backend - %d') \
                          % backend['id'])
                break

        if sm_vol_rec:
            # Update db
            sm_vol_rec['id'] = volume['id']
            sm_vol_rec['backend_id'] = backend['id']
            try:
                self.db.sm_volume_create(self.ctxt, sm_vol_rec)
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_("Failed to update volume in db"))

        else:
            raise exception.Error(_('Unable to create volume'))

    def delete_volume(self, volume):

        vol_rec = self.db.sm_volume_get(self.ctxt, volume['id'])

        try:
            # If compute runs on this node, detach could have disconnected SR
            backend_ref = self.db.sm_backend_conf_get(self.ctxt,
                                                      vol_rec['backend_id'])
            self._create_storage_repo(self.ctxt, backend_ref)
            self._volumeops.delete_volume_for_sm(vol_rec['vdi_uuid'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to delete vdi"))

        try:
            self.db.sm_volume_delete(self.ctxt, volume['id'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to delete volume in db"))

    def local_path(self, volume):
        return str(volume['id'])

    def undiscover_volume(self, volume):
        """Undiscover volume on a remote host."""
        pass

    def discover_volume(self, context, volume):
        return str(volume['id'])

    def check_for_setup_error(self):
        pass

    def create_export(self, context, volume):
        """Exports the volume."""
        # !!! TODO
        pass

    def remove_export(self, context, volume):
        """Removes an export for a logical volume."""
        pass

    def ensure_export(self, context, volume):
        """Safely, synchronously recreates an export for a logical volume."""
        pass

    def initialize_connection(self, volume, connector):
        try:
            xensm_properties = dict(self.db.sm_volume_get(self.ctxt,
                                                          volume['id']))
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to find volume in db"))

        # Keep the volume id key consistent with what ISCSI driver calls it
        xensm_properties['volume_id'] = xensm_properties['id']
        del xensm_properties['id']

        try:
            backend_conf = self.db.\
                           sm_backend_conf_get(self.ctxt,
                                               xensm_properties['backend_id'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to find backend in db"))

        params = self._convert_config_params(backend_conf['config_params'])

        xensm_properties['flavor_id'] = backend_conf['flavor_id']
        xensm_properties['sr_uuid'] = backend_conf['sr_uuid']
        xensm_properties['sr_type'] = backend_conf['sr_type']
        xensm_properties.update(params)
        xensm_properties['introduce_sr_keys'] = self.\
                                                _get_introduce_sr_keys(params)
        return {
            'driver_volume_type': 'xensm',
            'data': xensm_properties
        }

    def terminate_connection(self, volume, connector):
        pass
Example #9
0
class XenAPIConnection(driver.ComputeDriver):
    """A connection to XenServer or Xen Cloud Platform"""

    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._vmops = VMOps(self._session)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None

    @property
    def HostState(self):
        if not self._host_state:
            self._host_state = HostState(self._session)
        return self._host_state

    def init_host(self, host):
        #FIXME(armando): implement this
        #NOTE(armando): would we need a method
        #to call when shutting down the host?
        #e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def list_instances_detail(self):
        return self._vmops.list_instances_detail()

    def spawn(self, instance, network_info, block_device_mapping=None):
        """Create VM instance"""
        self._vmops.spawn(instance, network_info)

    def revert_resize(self, instance):
        """Reverts a resize, powering back on the instance"""
        self._vmops.revert_resize(instance)

    def finish_resize(self, instance, disk_info, network_info):
        """Completes a resize, turning on the migrated instance"""
        self._vmops.finish_resize(instance, disk_info, network_info)

    def snapshot(self, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(instance, image_id)

    def reboot(self, instance, network_info):
        """Reboot VM instance"""
        self._vmops.reboot(instance)

    def set_admin_password(self, instance, new_pass):
        """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, network_info):
        """Destroy VM instance"""
        self._vmops.destroy(instance, network_info)

    def pause(self, instance, callback):
        """Pause VM instance"""
        self._vmops.pause(instance, callback)

    def unpause(self, instance, callback):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance, callback)

    def migrate_disk_and_power_off(self, instance, dest):
        """Transfers the VHD of a running instance to another host, then shuts
        off the instance copies over the COW disk"""
        return self._vmops.migrate_disk_and_power_off(instance, dest)

    def suspend(self, instance, callback):
        """suspend the specified instance"""
        self._vmops.suspend(instance, callback)

    def resume(self, instance, callback):
        """resume the specified instance"""
        self._vmops.resume(instance, callback)

    def rescue(self, instance, callback, network_info):
        """Rescue the specified instance"""
        self._vmops.rescue(instance, callback)

    def unrescue(self, instance, callback, network_info):
        """Unrescue the specified instance"""
        self._vmops.unrescue(instance, callback)

    def poll_rescued_instances(self, timeout):
        """Poll for rescued instances"""
        self._vmops.poll_rescued_instances(timeout)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def inject_network_info(self, instance, network_info):
        """inject network info for specified instance"""
        self._vmops.inject_network_info(instance, network_info)

    def plug_vifs(self, instance_ref, network_info):
        self._vmops.plug_vifs(instance_ref, network_info)

    def get_info(self, instance_id):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_id)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def get_host_ip_addr(self):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return xs_url.netloc

    def attach_volume(self, instance_name, device_path, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(instance_name,
                                               device_path,
                                               mountpoint)

    def detach_volume(self, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(instance_name, mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return  {'address': xs_url.netloc,
                 'username': FLAGS.xenapi_connection_username,
                 'password': FLAGS.xenapi_connection_password}

    def update_available_resource(self, ctxt, host):
        """This method is supported only by libvirt."""
        return

    def compare_cpu(self, xml):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def ensure_filtering_rules_for_instance(self, instance_ref):
        """This method is supported only libvirt."""
        return

    def live_migration(self, context, instance_ref, dest,
                       post_method, recover_method):
        """This method is supported only by libvirt."""
        return

    def unfilter_instance(self, instance_ref, network_info):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def update_host_status(self):
        """Update the status info of the host, and return those values
            to the calling program."""
        return self.HostState.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the host. If 'refresh' is
           True, run the update first."""
        return self.HostState.get_host_stats(refresh=refresh)

    def set_host_enabled(self, host, enabled):
        """Sets the specified host's ability to accept new instances."""
        return self._vmops.set_host_enabled(host, enabled)
Example #10
0
 def __init__(self, url, user, pw):
     session = XenAPISession(url, user, pw)
     self._vmops = VMOps(session)
     self._volumeops = VolumeOps(session)
Example #11
0
class XenAPIConnection(object):
    """A connection to XenServer or Xen Cloud Platform"""

    def __init__(self, url, user, pw):
        session = XenAPISession(url, user, pw)
        self._vmops = VMOps(session)
        self._volumeops = VolumeOps(session)

    def init_host(self, host):
        #FIXME(armando): implement this
        #NOTE(armando): would we need a method
        #to call when shutting down the host?
        #e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def spawn(self, instance):
        """Create VM instance"""
        self._vmops.spawn(instance)

    def snapshot(self, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(instance, image_id)

    def reboot(self, instance):
        """Reboot VM instance"""
        self._vmops.reboot(instance)

    def set_admin_password(self, instance, new_pass):
        """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)

    def pause(self, instance, callback):
        """Pause VM instance"""
        self._vmops.pause(instance, callback)

    def unpause(self, instance, callback):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance, callback)

    def suspend(self, instance, callback):
        """suspend the specified instance"""
        self._vmops.suspend(instance, callback)

    def resume(self, instance, callback):
        """resume the specified instance"""
        self._vmops.resume(instance, callback)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def get_info(self, instance_id):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_id)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def attach_volume(self, instance_name, device_path, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(instance_name,
                                               device_path,
                                               mountpoint)

    def detach_volume(self, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(instance_name, mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return  {'address': xs_url.netloc,
                 'username': FLAGS.xenapi_connection_username,
                 'password': FLAGS.xenapi_connection_password}
Example #12
0
class XenAPIConnection(driver.ComputeDriver):
    """A connection to XenServer or Xen Cloud Platform"""

    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None
        self._product_version = self._session.get_product_version()
        self._vmops = VMOps(self._session, self._product_version)

    @property
    def host_state(self):
        if not self._host_state:
            self._host_state = HostState(self._session)
        return self._host_state

    def init_host(self, host):
        #FIXME(armando): implement this
        #NOTE(armando): would we need a method
        #to call when shutting down the host?
        #e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def list_instances_detail(self):
        return self._vmops.list_instances_detail()

    def spawn(self, context, instance, image_meta,
              network_info=None, block_device_info=None):
        """Create VM instance"""
        self._vmops.spawn(context, instance, image_meta, network_info)

    def confirm_migration(self, migration, instance, network_info):
        """Confirms a resize, destroying the source VM"""
        # TODO(Vek): Need to pass context in for access to auth_token
        self._vmops.confirm_migration(migration, instance, network_info)

    def finish_revert_migration(self, instance):
        """Finish reverting a resize, powering back on the instance"""
        self._vmops.finish_revert_migration(instance)

    def finish_migration(self, context, migration, instance, disk_info,
                         network_info, image_meta, resize_instance=False):
        """Completes a resize, turning on the migrated instance"""
        self._vmops.finish_migration(context, migration, instance, disk_info,
                                     network_info, image_meta, resize_instance)

    def snapshot(self, context, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(context, instance, image_id)

    def reboot(self, instance, network_info, reboot_type):
        """Reboot VM instance"""
        self._vmops.reboot(instance, reboot_type)

    def set_admin_password(self, instance, new_pass):
        """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, network_info, block_device_info=None):
        """Destroy VM instance"""
        self._vmops.destroy(instance, network_info)

    def pause(self, instance):
        """Pause VM instance"""
        self._vmops.pause(instance)

    def unpause(self, instance):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance)

    def migrate_disk_and_power_off(self, context, instance, dest,
                                   instance_type):
        """Transfers the VHD of a running instance to another host, then shuts
        off the instance copies over the COW disk"""
        return self._vmops.migrate_disk_and_power_off(context, instance,
                                                      dest, instance_type)

    def suspend(self, instance):
        """suspend the specified instance"""
        self._vmops.suspend(instance)

    def resume(self, instance):
        """resume the specified instance"""
        self._vmops.resume(instance)

    def rescue(self, context, instance, network_info, image_meta):
        """Rescue the specified instance"""
        self._vmops.rescue(context, instance, network_info, image_meta)

    def unrescue(self, instance, network_info):
        """Unrescue the specified instance"""
        self._vmops.unrescue(instance)

    def power_off(self, instance):
        """Power off the specified instance"""
        self._vmops.power_off(instance)

    def power_on(self, instance):
        """Power on the specified instance"""
        self._vmops.power_on(instance)

    def poll_rebooting_instances(self, timeout):
        """Poll for rebooting instances"""
        self._vmops.poll_rebooting_instances(timeout)

    def poll_rescued_instances(self, timeout):
        """Poll for rescued instances"""
        self._vmops.poll_rescued_instances(timeout)

    def poll_unconfirmed_resizes(self, resize_confirm_window):
        """Poll for unconfirmed resizes"""
        self._vmops.poll_unconfirmed_resizes(resize_confirm_window)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def inject_network_info(self, instance, network_info):
        """inject network info for specified instance"""
        self._vmops.inject_network_info(instance, network_info)

    def plug_vifs(self, instance_ref, network_info):
        """Plug VIFs into networks."""
        self._vmops.plug_vifs(instance_ref, network_info)

    def unplug_vifs(self, instance_ref, network_info):
        """Unplug VIFs from networks."""
        self._vmops.unplug_vifs(instance_ref, network_info)

    def get_info(self, instance_name):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_name)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_all_bw_usage(self, start_time, stop_time=None):
        """Return bandwidth usage info for each interface on each
           running VM"""
        bwusage = []
        start_time = time.mktime(start_time.timetuple())
        if stop_time:
            stop_time = time.mktime(stop_time.timetuple())
        for iusage in self._vmops.get_all_bw_usage(start_time, stop_time).\
                      values():
            for macaddr, usage in iusage.iteritems():
                vi = db.virtual_interface_get_by_address(
                                    context.get_admin_context(),
                                    macaddr)
                if vi:
                    bwusage.append(dict(virtual_interface=vi,
                                        bw_in=usage['bw_in'],
                                        bw_out=usage['bw_out']))
        return bwusage

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def get_vnc_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_vnc_console(instance)

    @staticmethod
    def get_host_ip_addr():
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return xs_url.netloc

    def attach_volume(self, connection_info, instance_name, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(connection_info,
                                             instance_name,
                                             mountpoint)

    def detach_volume(self, connection_info, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(connection_info,
                                             instance_name,
                                             mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return  {'address': xs_url.netloc,
                 'username': FLAGS.xenapi_connection_username,
                 'password': FLAGS.xenapi_connection_password}

    def update_available_resource(self, ctxt, host):
        """Updates compute manager resource info on ComputeNode table.

        This method is called when nova-compute launches, and
        whenever admin executes "nova-manage service update_resource".

        :param ctxt: security context
        :param host: hostname that compute manager is currently running

        """

        try:
            service_ref = db.service_get_all_compute_by_host(ctxt, host)[0]
        except exception.NotFound:
            raise exception.ComputeServiceUnavailable(host=host)

        host_stats = self.get_host_stats(refresh=True)

        # Updating host information
        total_ram_mb = host_stats['host_memory_total'] / (1024 * 1024)
        free_ram_mb = host_stats['host_memory_free'] / (1024 * 1024)
        total_disk_gb = host_stats['disk_total'] / (1024 * 1024 * 1024)
        used_disk_gb = host_stats['disk_used'] / (1024 * 1024 * 1024)

        dic = {'vcpus': 0,
               'memory_mb': total_ram_mb,
               'local_gb': total_disk_gb,
               'vcpus_used': 0,
               'memory_mb_used': total_ram_mb - free_ram_mb,
               'local_gb_used': used_disk_gb,
               'hypervisor_type': 'xen',
               'hypervisor_version': 0,
               'service_id': service_ref['id'],
               'cpu_info': host_stats['host_cpu_info']['cpu_count']}

        compute_node_ref = service_ref['compute_node']
        if not compute_node_ref:
            LOG.info(_('Compute_service record created for %s ') % host)
            db.compute_node_create(ctxt, dic)
        else:
            LOG.info(_('Compute_service record updated for %s ') % host)
            db.compute_node_update(ctxt, compute_node_ref[0]['id'], dic)

    def compare_cpu(self, xml):
        """This method is supported only by libvirt."""
        raise NotImplementedError('This method is supported only by libvirt.')

    def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
        """This method is supported only libvirt."""
        # NOTE(salvatore-orlando): it enforces security groups on
        # host initialization and live migration.
        # Live migration is not supported by XenAPI (as of 2011-11-09)
        # In XenAPI we do not assume instances running upon host initialization
        return

    def live_migration(self, context, instance_ref, dest,
                       post_method, recover_method, block_migration=False):
        """This method is supported only by libvirt."""
        return

    def unfilter_instance(self, instance_ref, network_info):
        """Removes security groups configured for an instance."""
        return self._vmops.unfilter_instance(instance_ref, network_info)

    def refresh_security_group_rules(self, security_group_id):
        """ Updates security group rules for all instances
            associated with a given security group
            Invoked when security group rules are updated
        """
        return self._vmops.refresh_security_group_rules(security_group_id)

    def refresh_security_group_members(self, security_group_id):
        """ Updates security group rules for all instances
            associated with a given security group
            Invoked when instances are added/removed to a security group
        """
        return self._vmops.refresh_security_group_members(security_group_id)

    def update_host_status(self):
        """Update the status info of the host, and return those values
            to the calling program."""
        return self.host_state.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the host. If 'refresh' is
           True, run the update first."""
        return self.host_state.get_host_stats(refresh=refresh)

    def host_power_action(self, host, action):
        """The only valid values for 'action' on XenServer are 'reboot' or
        'shutdown', even though the API also accepts 'startup'. As this is
        not technically possible on XenServer, since the host is the same
        physical machine as the hypervisor, if this is requested, we need to
        raise an exception.
        """
        if action in ("reboot", "shutdown"):
            return self._vmops.host_power_action(host, action)
        else:
            msg = _("Host startup on XenServer is not supported.")
            raise NotImplementedError(msg)

    def set_host_enabled(self, host, enabled):
        """Sets the specified host's ability to accept new instances."""
        return self._vmops.set_host_enabled(host, enabled)
Example #13
0
class XenSMDriver(VolumeDriver):
    def _convert_config_params(self, conf_str):
        params = dict([item.split("=") for item in conf_str.split()])
        return params

    def _get_introduce_sr_keys(self, params):
        if 'name_label' in params:
            del params['name_label']
        keys = params.keys()
        keys.append('sr_type')
        return keys

    def _create_storage_repo(self, context, backend_ref):
        """Either creates or introduces SR on host
        depending on whether it exists in xapi db."""
        params = self._convert_config_params(backend_ref['config_params'])
        if 'name_label' in params:
            label = params['name_label']
            del params['name_label']
        else:
            label = 'SR-' + str(backend_ref['id'])

        params['sr_type'] = backend_ref['sr_type']

        if backend_ref['sr_uuid'] == None:
            # run the sr create command
            try:
                LOG.debug(_('SR name = %s') % label)
                LOG.debug(_('Params: %s') % str(params))
                sr_uuid = self._volumeops.create_sr(label, params)
            # update sr_uuid and created in db
            except Exception as ex:
                LOG.debug(_("Failed to create sr %s...continuing") \
                          % str(backend_ref['id']))
                raise exception.Error(_('Create failed'))

            LOG.debug(_('SR UUID of new SR is: %s') % sr_uuid)
            try:
                self.db.sm_backend_conf_update(context, backend_ref['id'],
                                               dict(sr_uuid=sr_uuid))
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_("Failed to update db"))

        else:
            # sr introduce, if not already done
            try:
                self._volumeops.introduce_sr(backend_ref['sr_uuid'], label,
                                             params)
            except Exception as ex:
                LOG.exception(ex)
                LOG.debug(_("Failed to introduce sr %s...continuing") \
                          % str(backend_ref['id']))

    def _create_storage_repos(self, context):
        """Create/Introduce storage repositories at start."""
        backends = self.db.sm_backend_conf_get_all(context)
        for backend in backends:
            try:
                self._create_storage_repo(context, backend)
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_('Failed to reach backend %d') \
                                      % backend['id'])

    def __init__(self, *args, **kwargs):
        """Connect to the hypervisor."""

        # This driver leverages Xen storage manager, and hence requires
        # hypervisor to be Xen
        if FLAGS.connection_type != 'xenapi':
            raise exception.Error(_('XenSMDriver requires xenapi connection'))

        url = FLAGS.xenapi_connection_url
        username = FLAGS.xenapi_connection_username
        password = FLAGS.xenapi_connection_password
        try:
            session = XenAPISession(url, username, password)
            self._volumeops = VolumeOps(session)
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to initiate session"))

        super(XenSMDriver, self).__init__(execute=utils.execute,
                                          sync_exec=utils.execute,
                                          *args,
                                          **kwargs)

    def do_setup(self, ctxt):
        """Setup includes creating or introducing storage repos
           existing in the database and destroying deleted ones."""

        # TODO purge storage repos
        self.ctxt = ctxt
        self._create_storage_repos(ctxt)

    def create_volume(self, volume):
        """Creates a logical volume. Can optionally return a Dictionary of
        changes to the volume object to be persisted."""

        # For now the scheduling logic will be to try to fit the volume in
        # the first available backend.
        # TODO better scheduling once APIs are in place
        sm_vol_rec = None
        backends = self.db.sm_backend_conf_get_all(self.ctxt)
        for backend in backends:
            # Ensure that storage repo exists, if not create.
            # This needs to be done because if nova compute and
            # volume are both running on this host, then, as a
            # part of detach_volume, compute could potentially forget SR
            self._create_storage_repo(self.ctxt, backend)
            sm_vol_rec = self._volumeops.\
                              create_volume_for_sm(volume,
                                                   backend['sr_uuid'])
            if sm_vol_rec:
                LOG.debug(_('Volume will be created in backend - %d') \
                          % backend['id'])
                break

        if sm_vol_rec:
            # Update db
            sm_vol_rec['id'] = volume['id']
            sm_vol_rec['backend_id'] = backend['id']
            try:
                self.db.sm_volume_create(self.ctxt, sm_vol_rec)
            except Exception as ex:
                LOG.exception(ex)
                raise exception.Error(_("Failed to update volume in db"))

        else:
            raise exception.Error(_('Unable to create volume'))

    def delete_volume(self, volume):

        vol_rec = self.db.sm_volume_get(self.ctxt, volume['id'])

        try:
            # If compute runs on this node, detach could have disconnected SR
            backend_ref = self.db.sm_backend_conf_get(self.ctxt,
                                                      vol_rec['backend_id'])
            self._create_storage_repo(self.ctxt, backend_ref)
            self._volumeops.delete_volume_for_sm(vol_rec['vdi_uuid'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to delete vdi"))

        try:
            self.db.sm_volume_delete(self.ctxt, volume['id'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to delete volume in db"))

    def local_path(self, volume):
        return str(volume['id'])

    def undiscover_volume(self, volume):
        """Undiscover volume on a remote host."""
        pass

    def discover_volume(self, context, volume):
        return str(volume['id'])

    def check_for_setup_error(self):
        pass

    def create_export(self, context, volume):
        """Exports the volume."""
        # !!! TODO
        pass

    def remove_export(self, context, volume):
        """Removes an export for a logical volume."""
        pass

    def ensure_export(self, context, volume):
        """Safely, synchronously recreates an export for a logical volume."""
        pass

    def initialize_connection(self, volume, address):
        try:
            xensm_properties = dict(
                self.db.sm_volume_get(self.ctxt, volume['id']))
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to find volume in db"))

        # Keep the volume id key consistent with what ISCSI driver calls it
        xensm_properties['volume_id'] = xensm_properties['id']
        del xensm_properties['id']

        try:
            backend_conf = self.db.\
                           sm_backend_conf_get(self.ctxt,
                                               xensm_properties['backend_id'])
        except Exception as ex:
            LOG.exception(ex)
            raise exception.Error(_("Failed to find backend in db"))

        params = self._convert_config_params(backend_conf['config_params'])

        xensm_properties['flavor_id'] = backend_conf['flavor_id']
        xensm_properties['sr_uuid'] = backend_conf['sr_uuid']
        xensm_properties['sr_type'] = backend_conf['sr_type']
        xensm_properties.update(params)
        xensm_properties['introduce_sr_keys'] = self.\
                                                _get_introduce_sr_keys(params)
        return {'driver_volume_type': 'xensm', 'data': xensm_properties}

    def terminate_connection(self, volume, address):
        pass
Example #14
0
class XenAPIConnection(driver.ComputeDriver):
    """A connection to XenServer or Xen Cloud Platform"""

    def __init__(self, url, user, pw):
        super(XenAPIConnection, self).__init__()
        self._session = XenAPISession(url, user, pw)
        self._vmops = VMOps(self._session)
        self._volumeops = VolumeOps(self._session)
        self._host_state = None

    @property
    def HostState(self):
        if not self._host_state:
            self._host_state = HostState(self._session)
        return self._host_state

    def init_host(self, host):
        # FIXME(armando): implement this
        # NOTE(armando): would we need a method
        # to call when shutting down the host?
        # e.g. to do session logout?
        pass

    def list_instances(self):
        """List VM instances"""
        return self._vmops.list_instances()

    def list_instances_detail(self):
        return self._vmops.list_instances_detail()

    def spawn(self, context, instance, network_info=None, block_device_info=None):
        """Create VM instance"""
        self._vmops.spawn(context, instance, network_info)

    def confirm_migration(self, migration, instance, network_info):
        """Confirms a resize, destroying the source VM"""
        # TODO(Vek): Need to pass context in for access to auth_token
        self._vmops.confirm_migration(migration, instance, network_info)

    def finish_revert_migration(self, instance):
        """Finish reverting a resize, powering back on the instance"""
        self._vmops.finish_revert_migration(instance)

    def finish_migration(self, context, migration, instance, disk_info, network_info, resize_instance=False):
        """Completes a resize, turning on the migrated instance"""
        self._vmops.finish_migration(context, migration, instance, disk_info, network_info, resize_instance)

    def snapshot(self, context, instance, image_id):
        """ Create snapshot from a running VM instance """
        self._vmops.snapshot(context, instance, image_id)

    def reboot(self, instance, network_info, reboot_type):
        """Reboot VM instance"""
        self._vmops.reboot(instance, reboot_type)

    def set_admin_password(self, instance, new_pass):
        """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, network_info, cleanup=True):
        """Destroy VM instance"""
        self._vmops.destroy(instance, network_info)

    def pause(self, instance, callback):
        """Pause VM instance"""
        self._vmops.pause(instance, callback)

    def unpause(self, instance, callback):
        """Unpause paused VM instance"""
        self._vmops.unpause(instance, callback)

    def migrate_disk_and_power_off(self, context, instance, dest):
        """Transfers the VHD of a running instance to another host, then shuts
        off the instance copies over the COW disk"""
        return self._vmops.migrate_disk_and_power_off(context, instance, dest)

    def suspend(self, instance, callback):
        """suspend the specified instance"""
        self._vmops.suspend(instance, callback)

    def resume(self, instance, callback):
        """resume the specified instance"""
        self._vmops.resume(instance, callback)

    def rescue(self, context, instance, _callback, network_info):
        """Rescue the specified instance"""
        self._vmops.rescue(context, instance, _callback, network_info)

    def unrescue(self, instance, _callback, network_info):
        """Unrescue the specified instance"""
        self._vmops.unrescue(instance, _callback)

    def power_off(self, instance):
        """Power off the specified instance"""
        self._vmops.power_off(instance)

    def power_on(self, instance):
        """Power on the specified instance"""
        self._vmops.power_on(instance)

    def poll_rescued_instances(self, timeout):
        """Poll for rescued instances"""
        self._vmops.poll_rescued_instances(timeout)

    def poll_unconfirmed_resizes(self, resize_confirm_window):
        """Poll for unconfirmed resizes"""
        self._vmops.poll_unconfirmed_resizes(resize_confirm_window)

    def reset_network(self, instance):
        """reset networking for specified instance"""
        self._vmops.reset_network(instance)

    def inject_network_info(self, instance, network_info):
        """inject network info for specified instance"""
        self._vmops.inject_network_info(instance, network_info)

    def plug_vifs(self, instance_ref, network_info):
        self._vmops.plug_vifs(instance_ref, network_info)

    def get_info(self, instance_id):
        """Return data about VM instance"""
        return self._vmops.get_info(instance_id)

    def get_diagnostics(self, instance):
        """Return data about VM diagnostics"""
        return self._vmops.get_diagnostics(instance)

    def get_console_output(self, instance):
        """Return snapshot of console"""
        return self._vmops.get_console_output(instance)

    def get_ajax_console(self, instance):
        """Return link to instance's ajax console"""
        return self._vmops.get_ajax_console(instance)

    def get_host_ip_addr(self):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return xs_url.netloc

    def attach_volume(self, instance_name, device_path, mountpoint):
        """Attach volume storage to VM instance"""
        return self._volumeops.attach_volume(instance_name, device_path, mountpoint)

    def detach_volume(self, instance_name, mountpoint):
        """Detach volume storage to VM instance"""
        return self._volumeops.detach_volume(instance_name, mountpoint)

    def get_console_pool_info(self, console_type):
        xs_url = urlparse.urlparse(FLAGS.xenapi_connection_url)
        return {
            "address": xs_url.netloc,
            "username": FLAGS.xenapi_connection_username,
            "password": FLAGS.xenapi_connection_password,
        }

    def update_available_resource(self, ctxt, host):
        """This method is supported only by libvirt."""
        return

    def compare_cpu(self, xml):
        """This method is supported only by libvirt."""
        raise NotImplementedError("This method is supported only by libvirt.")

    def ensure_filtering_rules_for_instance(self, instance_ref, network_info):
        """This method is supported only libvirt."""
        return

    def live_migration(self, context, instance_ref, dest, post_method, recover_method, block_migration=False):
        """This method is supported only by libvirt."""
        return

    def unfilter_instance(self, instance_ref, network_info):
        """This method is supported only by libvirt."""
        raise NotImplementedError("This method is supported only by libvirt.")

    def update_host_status(self):
        """Update the status info of the host, and return those values
            to the calling program."""
        return self.HostState.update_status()

    def get_host_stats(self, refresh=False):
        """Return the current state of the host. If 'refresh' is
           True, run the update first."""
        return self.HostState.get_host_stats(refresh=refresh)

    def host_power_action(self, host, action):
        """The only valid values for 'action' on XenServer are 'reboot' or
        'shutdown', even though the API also accepts 'startup'. As this is
        not technically possible on XenServer, since the host is the same
        physical machine as the hypervisor, if this is requested, we need to
        raise an exception.
        """
        if action in ("reboot", "shutdown"):
            return self._vmops.host_power_action(host, action)
        else:
            msg = _("Host startup on XenServer is not supported.")
            raise NotImplementedError(msg)

    def set_host_enabled(self, host, enabled):
        """Sets the specified host's ability to accept new instances."""
        return self._vmops.set_host_enabled(host, enabled)
Example #15
0
 def __init__(self, url, user, pw):
     session = XenAPISession(url, user, pw)
     self._vmops = VMOps(session)
     self._volumeops = VolumeOps(session)