'Convert the volume to be of the new type.
The retype is performed only if the volume is not in use. Retype is NOP
if the backing doesn\'t exist. If disk type conversion is needed, the
volume is cloned. If disk type conversion is needed and the volume
contains snapshots, the backing is relocated instead of cloning. The
backing is also relocated if the current datastore is not compliant
with the new storage profile (if any). Finally, the storage profile of
the backing VM is updated.
:param ctxt: Context
:param volume: A dictionary describing the volume to retype
:param new_type: A dictionary describing the volume type to convert to
:param diff: A dictionary with the difference between the two types
:param host: A dictionary describing the host to migrate to, where
host[\'host\'] is its name, and host[\'capabilities\'] is a
dictionary of its reported capabilities (unused)
:returns: True if the retype occurred; False otherwise.'

def retype(self, ctxt, volume, new_type, diff, host):

    if self._in_use(volume):
        LOG.warning("Volume:    %s    is    in    use,    can't    retype.", volume['name'])
        return False
    backing = self.volumeops.get_backing(volume['name'])
    if (backing is None):
        LOG.debug("Backing    for    volume:    %s    doesn't    exist;    retype    is    NOP.", volume['name'])
        return True
    disk_type = VMwareVcVmdkDriver._get_disk_type(volume)
    new_disk_type = VMwareVcVmdkDriver._get_extra_spec_disk_type(new_type['id'])
    need_disk_type_conversion = (disk_type != new_disk_type)
    need_relocate = (need_disk_type_conversion and self.volumeops.snapshot_exists(backing))
    datastore = self.volumeops.get_datastore(backing)
    need_profile_change = False
    is_compliant = True
    new_profile = None
    if self._storage_policy_enabled:
        profile = self._get_storage_profile(volume)
        new_profile = self._get_extra_spec_storage_profile(new_type['id'])
        need_profile_change = (profile != new_profile)
        is_compliant = self.ds_sel.is_datastore_compliant(datastore, new_profile)
    if ((not need_disk_type_conversion) and is_compliant):
        LOG.debug("Backing:    %(backing)s    for    volume:    %(name)s    doesn't    need    disk    type    conversion.", {'backing': backing, 'name': volume['name']})
        if self._storage_policy_enabled:
            LOG.debug('Backing:    %(backing)s    for    volume:    %(name)s    is    compliant    with    the    new    profile:    %(new_profile)s.', {'backing': backing, 'name': volume['name'], 'new_profile': new_profile})
    else:
        req = {}
        req[hub.DatastoreSelector.SIZE_BYTES] = (volume['size'] * units.Gi)
        if need_relocate:
            LOG.debug('Backing:    %s    should    be    relocated.', backing)
            req[hub.DatastoreSelector.HARD_ANTI_AFFINITY_DS] = [datastore.value]
        if new_profile:
            req[hub.DatastoreSelector.PROFILE_NAME] = new_profile
        try:
            best_candidate = self._select_datastore(req)
        except vmdk_exceptions.NoValidDatastoreException:
            LOG.warning("There    are    no    datastores    matching    new    requirements;    can't    retype    volume:    %s.", volume['name'])
            return False
        (host, rp, summary) = best_candidate
        dc = self._get_dc(rp)
        folder = self._get_volume_group_folder(dc, volume['project_id'])
        new_datastore = summary.datastore
        if (datastore.value != new_datastore.value):
            LOG.debug('Backing:    %s    needs    to    be    relocated    for    retype.', backing)
            self.volumeops.relocate_backing(backing, new_datastore, rp, host, new_disk_type)
            self.volumeops.move_backing_to_folder(backing, folder)
        elif need_disk_type_conversion:
            LOG.debug('Backing:    %s    needs    to    be    cloned    for    retype.', backing)
            new_backing = None
            renamed = False
            tmp_name = uuidutils.generate_uuid()
            try:
                self.volumeops.rename_backing(backing, tmp_name)
                renamed = True
                new_backing = self.volumeops.clone_backing(volume['name'], backing, None, volumeops.FULL_CLONE_TYPE, datastore, disk_type=new_disk_type, host=host, resource_pool=rp, folder=folder)
                self._delete_temp_backing(backing)
                backing = new_backing
                self.volumeops.update_backing_uuid(backing, volume['id'])
                self.volumeops.update_backing_disk_uuid(backing, volume['id'])
            except exceptions.VimException:
                with excutils.save_and_reraise_exception():
                    LOG.exception('Error    occurred    while    cloning    backing:    %s    during    retype.', backing)
                    if (renamed and (not new_backing)):
                        LOG.debug('Undo    rename    of    backing:    %(backing)s;    changing    name    from    %(new_name)s    to    %(old_name)s.', {'backing': backing, 'new_name': tmp_name, 'old_name': volume['name']})
                        try:
                            self.volumeops.rename_backing(backing, volume['name'])
                        except exceptions.VimException:
                            LOG.warning('Changing    backing:    %(backing)s    name    from    %(new_name)s    to    %(old_name)s    failed.', {'backing': backing, 'new_name': tmp_name, 'old_name': volume['name']})
    if need_profile_change:
        LOG.debug('Backing:    %(backing)s    needs    a    profile    change    to:    %(profile)s.', {'backing': backing, 'profile': new_profile})
        profile_id = None
        if (new_profile is not None):
            profile_id = self.ds_sel.get_profile_id(new_profile)
        self.volumeops.change_backing_profile(backing, profile_id)
    LOG.debug('Volume:    %s    retype    is    done.', volume['name'])
    return True
