'Snapshot the given instance.
:param instance: nova.objects.instance.Instance object
:param name: name of the snapshot
:param extra_properties: dict of extra image properties to include
when creating the image.
:returns: A dict containing image metadata'

@check_instance_cell
@check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED, vm_states.PAUSED, vm_states.SUSPENDED])
def snapshot(self, context, instance, name, extra_properties=None):

    image_meta = self._create_image(context, instance, name, 'snapshot', extra_properties=extra_properties)
    instance.task_state = task_states.IMAGE_SNAPSHOT_PENDING
    try:
        instance.save(expected_task_state=[None])
    except (exception.InstanceNotFound, exception.UnexpectedDeletingTaskStateError) as ex:
        LOG.debug('Instance    disappeared    during    snapshot.', instance=instance)
        try:
            image_id = image_meta['id']
            self.image_api.delete(context, image_id)
            LOG.info('Image    %s    deleted    because    instance    deleted    before    snapshot    started.', image_id, instance=instance)
        except exception.ImageNotFound:
            pass
        except Exception as exc:
            LOG.warning('Error    while    trying    to    clean    up    image    %(img_id)s:    %(error_msg)s', {'img_id': image_meta['id'], 'error_msg': six.text_type(exc)})
        attr = 'task_state'
        state = task_states.DELETING
        if (type(ex) == exception.InstanceNotFound):
            attr = 'vm_state'
            state = vm_states.DELETED
        raise exception.InstanceInvalidState(attr=attr, instance_uuid=instance.uuid, state=state, method='snapshot')
    self.compute_rpcapi.snapshot_instance(context, instance, image_meta['id'])
    return image_meta
