'Snapshot a server instance.'

@wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.action('createImage')
@common.check_snapshots_enabled
@validation.schema(schema_servers.create_image, '2.0', '2.0')
@validation.schema(schema_servers.create_image, '2.1')
def _action_create_image(self, req, id, body):

    context = req.environ['nova.context']
    context.can((server_policies.SERVERS % 'create_image'))
    entity = body['createImage']
    image_name = common.normalize_name(entity['name'])
    metadata = entity.get('metadata', {})
    if api_version_request.is_supported(req, max_version=api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
        common.check_img_metadata_properties_quota(context, metadata)
    instance = self._get_server(context, req, id)
    bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(context, instance.uuid)
    try:
        if compute_utils.is_volume_backed_instance(context, instance, bdms):
            context.can((server_policies.SERVERS % 'create_image:allow_volume_backed'))
            image = self.compute_api.snapshot_volume_backed(context, instance, image_name, extra_properties=metadata)
        else:
            image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata)
    except exception.InstanceUnknownCell as e:
        raise exc.HTTPNotFound(explanation=e.format_message())
    except exception.InstanceInvalidState as state_error:
        common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id)
    except exception.Invalid as err:
        raise exc.HTTPBadRequest(explanation=err.format_message())
    except exception.OverQuota as e:
        raise exc.HTTPForbidden(explanation=e.format_message())
    if api_version_request.is_supported(req, '2.45'):
        return {'image_id': image['id']}
    image_id = str(image['id'])
    image_ref = glance.generate_image_url(image_id)
    resp = webob.Response(status_int=202)
    resp.headers['Location'] = image_ref
    return resp
