Skip to content

Commit 71f1850

Browse files
authored
Replace timestamps; fix nova metadata calls (#7)
* extend test cases; fix tox * filter timestamps; fix nova mapping of metadata calls * no python3.7 check * fix py2/py3 compatibility for unicode * fix py37 * toxenv
1 parent 27ec037 commit 71f1850

File tree

10 files changed

+98
-9
lines changed

10 files changed

+98
-9
lines changed

.travis.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ matrix:
77
env: TOXENV=py27
88
- python: 3.5
99
env: TOXENV=py35
10+
- python: 3.6
11+
env: TOXENV=py36
12+
- python: 3.7
13+
dist: xenial
14+
sudo: true
15+
env: TOXENV=py37
1016
- env: TOXENV=pep8
1117

1218
install:

doc/cadf.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,17 @@ custom_actions:
122122
123123
#### CADF target type URI
124124
125-
The *target type URI* is a CADF specific representation of the request's target URI consisting of
126-
a service-specific prefix and the target URI without version or UUID strings.
125+
A *target type URI* is a CADF specific representation of the request's target URI consisting of
126+
the service-specific prefix `service/<service_type>` and the target URI without version, UUIDs and name.
127+
This middleware relies on a [configuration](../etc/) to identify the parts of the target URI which should be replaced.
127128
128-
In most cases this middleware builds the target type URI by concatenating the `service/<service_type>` prefix and
129-
all parts of the target URI which do not contain a UUID.
130-
In case a UUID is found, it's substituted by the singular of the previous part.
131-
Should this default behaviour not suffice, writing a [custom strategy](./watcher/target_type_uri_strategy.py) might be required.
129+
The default replacement strategy determines the target type URI of a request by its path in the following order:
130+
1. Check whether any of the given `regex_path_mapping`s applies. Replace and return.
131+
2. Check whether any of the given keywords appear in the path.
132+
Replace the part following the `keyword` with its singular if its not a `keyword` or `keyword_exclusion`.
133+
3. Determine target type URI by replacing UUIDs with the singular of the previous part.
134+
135+
The default behaviour can be replaced by implementing a [custom strategy](./watcher/target_type_uri_strategy.py).
132136
133137
Examples:
134138
```

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ datadog
22
pycadf!=2.0.0,>=1.1.0 # Apache-2.0
33
WebOb
44
six
5+
pyyaml

tox.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ envlist = py27,py35,pep8
66

77
[testenv]
88
usedevelop = True
9-
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
9+
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://raw.githubusercontent.com/openstack/requirements/master/upper-constraints.txt} {opts} {packages}
1010
setenv = VIRTUAL_ENV={envdir}
1111
BRANCH_NAME=master
1212
CLIENT_NAME=watcher

watcher/cadf_strategy.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def _cadf_action_from_body(self, json_body):
227227
"""
228228
cadf_action = taxonomy.UNKNOWN
229229
try:
230-
if isinstance(json_body, str) or isinstance(json_body, unicode):
230+
if isinstance(json_body, str) or isinstance(json_body, six.string_types):
231231
json_body = common.load_json_dict(json_body)
232232
# the 1st key specifies the action type
233233
os_action = next(iter(json_body))
@@ -349,6 +349,9 @@ def _determine_target_type_uri_by_parts(self, path_parts):
349349
# ensure no versions or uids are added to the target_type_uri even if the path starts with one
350350
if common.is_version_string(part) or common.is_uid_string(part):
351351
continue
352+
elif common.is_timestamp_string(part):
353+
target_type_uri.append('version')
354+
continue
352355
if len(part) > 1:
353356
target_type_uri.append(part)
354357

watcher/common.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
UID_REGEX = '[a-fA-F0-9-?]{32,36}'
2323
VERSION_REGEX = '^v(?:\d+\.)?(?:\d+\.)?(\*|\d+)$'
24+
TIMESTAMP_REGEX = '^\d{4}-\d{2}-\d{2}$'
2425

2526
METHOD_ACTION_MAP = {
2627
'GET': taxonomy.ACTION_READ,
@@ -200,6 +201,18 @@ def is_version_string(string):
200201
return False
201202

202203

204+
def is_timestamp_string(string):
205+
"""
206+
check if the string is a timestamp
207+
:param string: potential timestamp string
208+
:return: bool
209+
"""
210+
timestamp_regex = re.compile(TIMESTAMP_REGEX)
211+
if timestamp_regex.match(string) or str.lower(string) == 'latest':
212+
return True
213+
return False
214+
215+
203216
def endswith_version(string):
204217
"""
205218
check whether a string ends with a version

watcher/tests/fixtures/nova-complex.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
path_keywords:
2+
- block-device-mapping
23
- consoles
34
- entries
45
- extensions
@@ -53,4 +54,7 @@ path_keywords:
5354
keyword_exclusions:
5455
- configure-project
5556
- label
56-
- disable-log-reason
57+
- disable-log-reason
58+
59+
regex_path_mapping:
60+
- '\S+/meta-data/block-device-mapping/\S+$': 'version/meta-data/block-device-mapping/block-device-mapping'

watcher/tests/test_common.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@ def test_is_uid_string(self):
5555
expected
5656
)
5757

58+
def test_is_timestamp_string(self):
59+
stimuli = {
60+
'7df1acb1a2f2478eadf3f350d3f44c51': False,
61+
'v2': False,
62+
'2009-04-04': True,
63+
'2008-02-01': True,
64+
'2016-09-02': True,
65+
}
66+
67+
for stim, expected in six.iteritems(stimuli):
68+
is_timestamp = common.is_timestamp_string(stim)
69+
self.assertEqual(
70+
is_timestamp,
71+
expected
72+
)
73+
5874
def test_trim_prefix(self):
5975
self.assertEqual(
6076
common.trim_prefix('service/storage/object/account/container', 'service/storage/object'),

watcher/tests/test_designate.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ def test_target_type_uri(self):
175175
),
176176
'expected': 'service/dns/root'
177177
},
178+
{
179+
'request': fake.create_request(
180+
path='/v2/zones/something.com'
181+
),
182+
'expected': 'service/dns/zones/zone'
183+
},
178184
]
179185

180186
for stim in stimuli:

watcher/tests/test_nova.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,42 @@ def test_target_type_uri(self):
249249
),
250250
'expected': 'service/compute/root'
251251
},
252+
{
253+
'request': fake.create_request(
254+
path='/2009-04-04/meta-data/block-device-mapping'
255+
),
256+
'expected': 'service/compute/version/meta-data/block-device-mapping'
257+
},
258+
{
259+
'request': fake.create_request(
260+
path='/2009-04-04/meta-data/block-device-mapping/root'
261+
),
262+
'expected': 'service/compute/version/meta-data/block-device-mapping/block-device-mapping'
263+
},
264+
{
265+
'request': fake.create_request(
266+
path='/2012-01-12/meta-data'
267+
),
268+
'expected': 'service/compute/version/meta-data'
269+
},
270+
{
271+
'request': fake.create_request(
272+
path='/2012-01-12/meta-data/hostname'
273+
),
274+
'expected': 'service/compute/version/meta-data/hostname'
275+
},
276+
{
277+
'request': fake.create_request(
278+
path='/2012-01-12'
279+
),
280+
'expected': 'service/compute/version'
281+
},
282+
{
283+
'request': fake.create_request(
284+
path='/latest/meta-data'
285+
),
286+
'expected': 'service/compute/version/meta-data'
287+
}
252288
]
253289

254290
for stim in stimuli:

0 commit comments

Comments
 (0)