Support filtering by schema namespace

This PS adds support for filtering by schema namespace. According
to docs [0], "schema=promenade [should] select all kind and version
schemas owned by promenade, or schema=promenade/Node [should] select
all versions", for example.

This PS also adds bucket.status filtering support to rendered-documents
endpoint which should also be supported according to docs [1].

[0] http://deckhand.readthedocs.io/en/latest/api_ref.html#get-revisions-revision-id-documents
[1] http://deckhand.readthedocs.io/en/latest/api_ref.html#get-revisions-revision-id-rendered-documents

Change-Id: I43f4c0158096a23b934f4446bfbeaaf3bd7365e4
This commit is contained in:
Felipe Monteiro 2017-11-27 15:41:46 +00:00
parent 19d6a98f4f
commit fb15186b44
4 changed files with 111 additions and 4 deletions

View File

@ -93,7 +93,7 @@ class RenderedDocumentsResource(api_base.BaseResource):
@policy.authorize('deckhand:list_cleartext_documents')
@common.sanitize_params([
'schema', 'metadata.name', 'metadata.label'])
'schema', 'metadata.name', 'metadata.label', 'status.bucket'])
def on_get(self, req, resp, sanitized_params, revision_id):
include_encrypted = policy.conditional_authorize(
'deckhand:list_encrypted_documents', req.context, do_raise=False)

View File

@ -19,6 +19,7 @@ import ast
import copy
import functools
import hashlib
import re
import threading
from oslo_config import cfg
@ -524,6 +525,16 @@ def _update_revision_history(documents):
return documents
def _add_microversion(value):
"""Hack for coercing all Deckhand schema fields (``schema`` and
``metadata.schema``) into ending with v1.0 rather than v1, for example.
"""
microversion_re = r'^.*/.*/v[0-9]{1}$'
if re.match(value, microversion_re):
return value + '.0'
return value
def _apply_filters(dct, **filters):
"""Apply filters to ``dct``.
@ -571,13 +582,32 @@ def _apply_filters(dct, **filters):
filter_val.items()).issubset(set(actual_val.items()))
if not is_subset:
return False
# Else both filters are string literals.
else:
# Filtering by schema must support namespace matching
# (e.g. schema=promenade) such that all kind and schema
# documents with promenade namespace are returned, or
# (e.g. schema=promenade/Node) such that all version
# schemas with namespace=schema and kind=Node are returned.
if isinstance(actual_val, bool):
filter_val = _transform_filter_bool(filter_val)
# Else both filters are string literals.
if filter_key in ['metadata.schema', 'schema']:
if not actual_val.startswith(filter_val):
if filter_key in ['schema', 'metadata.schema']:
actual_val = _add_microversion(actual_val)
filter_val = _add_microversion(filter_val)
parts = actual_val.split('/')[:2]
if len(parts) == 2:
actual_namespace, actual_kind = parts
elif len(parts) == 1:
actual_namespace = parts[0]
actual_kind = ''
else:
actual_namespace = actual_kind = ''
actual_minus_version = actual_namespace + '/' + actual_kind
if not (filter_val == actual_val or
actual_minus_version == filter_val or
actual_namespace == filter_val):
return False
else:
if actual_val != filter_val:

View File

@ -0,0 +1,47 @@
# 1. Test invalid cases for the "schema" filter:
# * Partial namespace is invalid, e.g.: schema=prom
# * Partial kind is invalid, e.g.: schema=promenade/No
# 2. Test that filtering by wrong version returns no results.
defaults:
request_headers:
content-type: application/x-yaml
response_headers:
content-type: application/x-yaml
tests:
- name: purge
desc: Begin testing from known state.
DELETE: /api/v1.0/revisions
status: 204
response_headers: null
- name: initialize
desc: Create initial documents
PUT: /api/v1.0/buckets/mop/documents
status: 200
data: <@resources/design-doc-layering-sample.yaml
- name: filter_by_schema_partial_namespace
desc: Verify revision documents do not return results for partial namespace
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents
query_parameters:
schema: exam
status: 200
response_multidoc_jsonpaths: null
- name: filter_by_schema_partial_kind
desc: Verify revision documents do not return results for partial kind
GET: /api/v1.0/revisions/$HISTORY['initialize'].$RESPONSE['$.[0].status.revision']/documents
query_parameters:
schema: example/Ki
status: 200
response_multidoc_jsonpaths: null
- name: filter_by_schema_incorrect_version
desc: Verify revision documents do not return results for incorrect version
GET: /api/v1.0/revisions/$HISTORY['initialize'].$RESPONSE['$.[0].status.revision']/documents
query_parameters:
schema: example/Kind/v2
status: 200
response_multidoc_jsonpaths: null

View File

@ -37,6 +37,36 @@ tests:
$.[0].metadata.name: layering-policy
$.[0].schema: deckhand/LayeringPolicy/v1
- name: filter_by_schema_namespace
desc: Verify revision documents filtered by schema namespace
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents
query_parameters:
schema: example
status: 200
response_multidoc_jsonpaths:
$.`len`: 3
$.[0].metadata.name: global-1234
$.[0].schema: example/Kind/v1
$.[1].metadata.name: region-1234
$.[1].schema: example/Kind/v1
$.[2].metadata.name: site-1234
$.[2].schema: example/Kind/v1
- name: filter_by_schema_namespace_and_kind
desc: Verify revision documents filtered by schema namespace and kind
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents
query_parameters:
schema: example/Kind
status: 200
response_multidoc_jsonpaths:
$.`len`: 3
$.[0].metadata.name: global-1234
$.[0].schema: example/Kind/v1
$.[1].metadata.name: region-1234
$.[1].schema: example/Kind/v1
$.[2].metadata.name: site-1234
$.[2].schema: example/Kind/v1
- name: filter_by_metadata_name
desc: Verify revision documents filtered by metadata.name
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents