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:
parent
19d6a98f4f
commit
fb15186b44
@ -93,7 +93,7 @@ class RenderedDocumentsResource(api_base.BaseResource):
|
|||||||
|
|
||||||
@policy.authorize('deckhand:list_cleartext_documents')
|
@policy.authorize('deckhand:list_cleartext_documents')
|
||||||
@common.sanitize_params([
|
@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):
|
def on_get(self, req, resp, sanitized_params, revision_id):
|
||||||
include_encrypted = policy.conditional_authorize(
|
include_encrypted = policy.conditional_authorize(
|
||||||
'deckhand:list_encrypted_documents', req.context, do_raise=False)
|
'deckhand:list_encrypted_documents', req.context, do_raise=False)
|
||||||
|
@ -19,6 +19,7 @@ import ast
|
|||||||
import copy
|
import copy
|
||||||
import functools
|
import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import re
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -524,6 +525,16 @@ def _update_revision_history(documents):
|
|||||||
return 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):
|
def _apply_filters(dct, **filters):
|
||||||
"""Apply filters to ``dct``.
|
"""Apply filters to ``dct``.
|
||||||
|
|
||||||
@ -571,13 +582,32 @@ def _apply_filters(dct, **filters):
|
|||||||
filter_val.items()).issubset(set(actual_val.items()))
|
filter_val.items()).issubset(set(actual_val.items()))
|
||||||
if not is_subset:
|
if not is_subset:
|
||||||
return False
|
return False
|
||||||
|
# Else both filters are string literals.
|
||||||
else:
|
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):
|
if isinstance(actual_val, bool):
|
||||||
filter_val = _transform_filter_bool(filter_val)
|
filter_val = _transform_filter_bool(filter_val)
|
||||||
|
|
||||||
# Else both filters are string literals.
|
if filter_key in ['schema', 'metadata.schema']:
|
||||||
if filter_key in ['metadata.schema', 'schema']:
|
actual_val = _add_microversion(actual_val)
|
||||||
if not actual_val.startswith(filter_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
|
return False
|
||||||
else:
|
else:
|
||||||
if actual_val != filter_val:
|
if actual_val != filter_val:
|
||||||
|
@ -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
|
@ -37,6 +37,36 @@ tests:
|
|||||||
$.[0].metadata.name: layering-policy
|
$.[0].metadata.name: layering-policy
|
||||||
$.[0].schema: deckhand/LayeringPolicy/v1
|
$.[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
|
- name: filter_by_metadata_name
|
||||||
desc: Verify revision documents filtered by metadata.name
|
desc: Verify revision documents filtered by metadata.name
|
||||||
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents
|
GET: /api/v1.0/revisions/$RESPONSE['$.[0].status.revision']/documents
|
||||||
|
Loading…
x
Reference in New Issue
Block a user