Skip to content

Commit 7714303

Browse files
authored
Merge pull request #165 from jasonrahm/fix.subpath
Adding transform support for subPath
2 parents f38356a + 1dee8fa commit 7714303

3 files changed

Lines changed: 107 additions & 14 deletions

File tree

icontrol/session.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015-2016 F5 Networks Inc.
1+
# Copyright 2019 F5 Networks Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -181,7 +181,8 @@ def _validate_uri_parts(
181181
_validate_name_partition_subpath(partition)
182182
if not kwargs.get('transform_name', False):
183183
_validate_name_partition_subpath(name)
184-
_validate_name_partition_subpath(sub_path)
184+
if not kwargs.get('transform_subpath', False):
185+
_validate_name_partition_subpath(sub_path)
185186
if suffix_collections:
186187
_validate_suffix_collections(suffix_collections)
187188
return True
@@ -207,8 +208,8 @@ def generate_bigip_uri(base_uri, partition, name, sub_path, suffix, **kwargs):
207208
'https://0.0.0.0/mgmt/tm/ltm/nat/thwocky'
208209
209210
::Warning: There are cases where '/' and '~' characters are valid in the
210-
object name. This is indicated by passing 'transform_name' boolean as
211-
True, by default this is set to False.
211+
object name or subPath. This is indicated by passing the 'transform_name' or 'transform_subpath' boolean
212+
respectively as True. By default this is set to False.
212213
'''
213214

214215
_validate_uri_parts(base_uri, partition, name, sub_path, suffix,
@@ -217,6 +218,9 @@ def generate_bigip_uri(base_uri, partition, name, sub_path, suffix, **kwargs):
217218
if kwargs.get('transform_name', False):
218219
if name != '':
219220
name = name.replace('/', '~')
221+
if kwargs.get('transform_subpath', False):
222+
if sub_path != '':
223+
sub_path = sub_path.replace('/', '~')
220224
if partition != '':
221225
partition = '~' + partition
222226
else:
@@ -260,10 +264,12 @@ def wrapper(self, RIC_base_uri, **kwargs):
260264
identifier, kwargs = _unique_resource_identifier_from_kwargs(**kwargs)
261265
uri_as_parts = kwargs.pop('uri_as_parts', False)
262266
transform_name = kwargs.pop('transform_name', False)
267+
transform_subpath = kwargs.pop('transform_subpath', False)
263268
if uri_as_parts:
264269
REST_uri = generate_bigip_uri(RIC_base_uri, partition, identifier,
265270
sub_path, suffix,
266271
transform_name=transform_name,
272+
transform_subpath=transform_subpath,
267273
**kwargs)
268274
else:
269275
REST_uri = RIC_base_uri

icontrol/test/functional/test_session.py

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015-2016 F5 Networks Inc.
1+
# Copyright 2019 F5 Networks Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -93,6 +93,36 @@ def skip_module_missing(request, modules, opt_bigip, opt_username, opt_password,
9393
}
9494

9595

96+
iapp_templ_data_subpath_v11 = {
97+
"name": "test_templ_subpath",
98+
"partition": "Common",
99+
"actions": {
100+
"definition":
101+
{
102+
"implementation": '''tmsh::create { net vlan v102 }
103+
tmsh::create { net self self.v102 address 192.168.1.5/24 vlan v102 }
104+
tmsh::create { gtm datacenter dc1 }
105+
tmsh::create { auth partition part1 }
106+
tmsh::cd { /part1 }
107+
tmsh::create { ltm virtual v1 destination 192.168.1.100:80 }
108+
tmsh::cd { /Common }
109+
tmsh::create { gtm server ltm11 addresses add { 192.168.1.5 } datacenter dc1
110+
virtual-servers replace-all-with { /part1/v1 { destination 192.168.1.100:80 } } }
111+
tmsh::cd { /part1 }
112+
tmsh::create { gtm pool p1 members replace-all-with { /Common/ltm11:/part1/v1 } }''',
113+
"presentation": ""
114+
}
115+
}
116+
}
117+
118+
119+
iapp_serv_data_subpath = {
120+
"name": "test_serv_subpath",
121+
"partition": "Common",
122+
"template": "/Common/test_templ_subpath"
123+
}
124+
125+
96126
@pytest.fixture
97127
def setup_subpath(request, ICR, BASE_URL):
98128
app_templ_url = BASE_URL + 'sys/application/template/'
@@ -127,6 +157,40 @@ def teardown_iapp():
127157
return app_serv_url
128158

129159

160+
@pytest.fixture
161+
def setup_subpath_alt(request, ICR, BASE_URL):
162+
app_templ_url = BASE_URL + 'sys/application/template/'
163+
app_serv_url = BASE_URL + 'sys/application/service/'
164+
165+
def teardown_iapp():
166+
try:
167+
ICR.delete(
168+
app_serv_url, uri_as_parts=True,
169+
name='test_serv_subpath', partition='Common',
170+
subPath='test_serv_subpath.app')
171+
except Exception:
172+
pass
173+
174+
try:
175+
ICR.delete(
176+
app_templ_url, uri_as_parts=True,
177+
name='test_templ_subpath', partition='Common')
178+
except Exception:
179+
pass
180+
181+
teardown_iapp()
182+
ICR.post(app_templ_url, json=iapp_templ_data_subpath_v11)
183+
try:
184+
ICR.post(app_serv_url, json=iapp_serv_data_subpath)
185+
except HTTPError as ex:
186+
# The creation of an iapp service does cause a 404 error in bigip
187+
# versions up to but excluding 12.0
188+
if ex.response.status_code == 404:
189+
pass
190+
request.addfinalizer(teardown_iapp)
191+
return app_serv_url
192+
193+
130194
def teardown_nat(request, icr, url, name, partition):
131195
'''Remove the nat object that we create during a test '''
132196
def teardown():
@@ -165,7 +229,7 @@ def invalid_token_credentials(user, password, url):
165229
with pytest.raises(HTTPError) as err:
166230
icr.get(url)
167231
return (err.value.response.status_code == 401 and
168-
'Authentication required!' in err.value.message)
232+
'Authentication required!' in str(err.value))
169233

170234

171235
def test_get_with_subpath(setup_subpath, ICR, BASE_URL):
@@ -185,6 +249,25 @@ def test_get_with_subpath(setup_subpath, ICR, BASE_URL):
185249
assert data['items'][0]['name'] == 'test_pool'
186250

187251

252+
@pytest.mark.skipif(
253+
LooseVersion(pytest.config.getoption('--release')) >= LooseVersion(
254+
'12.0.0'),
255+
reason='No GTM Pool type, introduced in 12.0+'
256+
)
257+
def test_get_with_subpath_transform(setup_subpath_alt, ICR, BASE_URL):
258+
app_serv_url = setup_subpath_alt
259+
res = ICR.get(
260+
app_serv_url, name='test_serv_subpath',
261+
partition='Common', subPath='test_serv_subpath.app')
262+
assert res.status_code == 200
263+
pool_uri = BASE_URL + 'gtm/pool/~part1~p1/members/'
264+
poolmem_res = ICR.get(pool_uri, name='v1', partition='Common', subPath='ltm11:/part1')
265+
assert poolmem_res.status_code == 200
266+
data = poolmem_res.json()
267+
assert data['items'][0]['name'] == 'v1'
268+
assert data['items'][0]['subPath'] == 'ltm11:/part1'
269+
270+
188271
def test_get(ICR, GET_URL):
189272
'''Test a GET request to a valid url
190273

icontrol/test/unit/test_session.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015-2016 F5 Networks Inc.
1+
# Copyright 2019 F5 Networks Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -57,7 +57,8 @@ def uparts():
5757
'name': 'foobar1',
5858
'sub_path': '',
5959
'suffix': '/members/m1',
60-
'transform_name': False}
60+
'transform_name': False,
61+
'transform_subpath': False}
6162
return parts_dict
6263

6364

@@ -68,7 +69,8 @@ def transform_name():
6869
'name': 'foobar1: 1.1.1.1/24 bar1: /Common/DC1',
6970
'sub_path': '',
7071
'suffix': '/members/m1',
71-
'transform_name': True}
72+
'transform_name': True,
73+
'transform_subpath': False}
7274
return parts_dict
7375

7476

@@ -79,7 +81,8 @@ def uparts_with_subpath():
7981
'name': 'foobar1',
8082
'sub_path': 'sp',
8183
'suffix': '/members/m1',
82-
'transform_name': False}
84+
'transform_name': False,
85+
'transform_subpath': False}
8386
return parts_dict
8487

8588

@@ -88,9 +91,10 @@ def transform_name_w_subpath():
8891
parts_dict = {'base_uri': 'https://0.0.0.0/mgmt/tm/root/RESTiface/',
8992
'partition': 'BIGCUSTOMER',
9093
'name': 'foobar1: 1.1.1.1/24 bar1: /Common/DC1',
91-
'sub_path': 'sp',
94+
'sub_path': 'ltm:/sp',
9295
'suffix': '/members/m1',
93-
'transform_name': True}
96+
'transform_name': True,
97+
'transform_subpath': True}
9498
return parts_dict
9599

96100

@@ -306,7 +310,7 @@ def test_correct_uri_transformed_nameless_subpath(transform_name_w_subpath):
306310
transform_name_w_subpath['name'] = ''
307311
uri = session.generate_bigip_uri(**transform_name_w_subpath)
308312
assert uri ==\
309-
"https://0.0.0.0/mgmt/tm/root/RESTiface/~BIGCUSTOMER~sp/members/m1"
313+
"https://0.0.0.0/mgmt/tm/root/RESTiface/~BIGCUSTOMER~ltm:~sp/members/m1"
310314

311315

312316
def test_correct_uri_transformed_partitionless_and_nameless(transform_name):
@@ -376,7 +380,7 @@ def test_correct_uri_transformed_nameless_and_suffixless_subpath(
376380
transform_name_w_subpath['name'] = ''
377381
transform_name_w_subpath['suffix'] = ''
378382
uri = session.generate_bigip_uri(**transform_name_w_subpath)
379-
assert uri == 'https://0.0.0.0/mgmt/tm/root/RESTiface/~BIGCUSTOMER~sp'
383+
assert uri == 'https://0.0.0.0/mgmt/tm/root/RESTiface/~BIGCUSTOMER~ltm:~sp'
380384

381385

382386
def test_correct_uri_construction_mgmt_shared(uparts_shared):

0 commit comments

Comments
 (0)