Skip to content

Commit 5d4f71d

Browse files
author
pjbreaux
authored
Merge pull request #496 from caphrim007/add-gtm-irule-support
Adds GTM iRule api support
2 parents 60abd57 + 4b9f576 commit 5d4f71d

9 files changed

Lines changed: 332 additions & 1 deletion

File tree

conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#
1515

1616
from f5.bigip import BigIP
17+
from f5.bigip import ManagementRoot
1718
import mock
1819
import pytest
1920

@@ -76,6 +77,13 @@ def bigip(opt_bigip, opt_username, opt_password, opt_port, scope="module"):
7677
return b
7778

7879

80+
@pytest.fixture
81+
def mgmt_root(opt_bigip, opt_username, opt_password, opt_port, scope="module"):
82+
'''bigip fixture'''
83+
m = ManagementRoot(opt_bigip, opt_username, opt_password, port=opt_port)
84+
return m
85+
86+
7987
@pytest.fixture
8088
def opt_release(request):
8189
return request.config.getoption("--release")

f5/bigip/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from f5.bigip.shared import Shared
2828
from f5.bigip.tm.auth import Auth as TmAuth
2929
from f5.bigip.tm.cm import Cm as TmCm
30+
from f5.bigip.tm.gtm import Gtm
3031
from f5.bigip.tm.ltm import Ltm
3132
from f5.bigip.tm.net import Net
3233
from f5.bigip.tm.shared import Shared as TmShared
@@ -92,4 +93,4 @@ def __init__(self, hostname, username, password, **kwargs):
9293
super(BigIP, self).__init__(hostname, username, password, **kwargs)
9394
self._meta_data['uri'] = self._meta_data['uri'] + 'tm/'
9495
self._meta_data['allowed_lazy_attributes'] =\
95-
[TmAuth, TmCm, Ltm, Net, TmShared, Sys, Transactions]
96+
[TmAuth, TmCm, Ltm, Gtm, Net, TmShared, Sys, Transactions]

f5/bigip/tm/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from f5.bigip.tm.auth import Auth
2222
from f5.bigip.tm.cm import Cm
23+
from f5.bigip.tm.gtm import Gtm
2324
from f5.bigip.tm.ltm import Ltm
2425
from f5.bigip.tm.net import Net
2526
from f5.bigip.tm.shared import Shared
@@ -34,6 +35,7 @@ def __init__(self, bigip):
3435
self._meta_data['allowed_lazy_attributes'] = [
3536
Auth,
3637
Cm,
38+
Gtm,
3739
Ltm,
3840
Net,
3941
Shared,

f5/bigip/tm/gtm/__init__.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# coding=utf-8
2+
#
3+
# Copyright 2015-2016 F5 Networks Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
"""BIG-IP® Global Traffic Manager™ (GTM®) module.
19+
20+
REST URI
21+
``http://localhost/mgmt/tm/gtm/``
22+
23+
GUI Path
24+
``DNS``
25+
26+
REST Kind
27+
``tm:gtm:*``
28+
"""
29+
30+
31+
from f5.bigip.resource import OrganizingCollection
32+
from f5.bigip.tm.gtm.rule import Rules
33+
34+
35+
class Gtm(OrganizingCollection):
36+
"""BIG-IP® Global Traffic Manager (GTM) organizing collection."""
37+
def __init__(self, tm):
38+
super(Gtm, self).__init__(tm)
39+
self._meta_data['allowed_lazy_attributes'] = [
40+
Rules
41+
]

f5/bigip/tm/gtm/rule.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# coding=utf-8
2+
#
3+
# Copyright 2014-2015 F5 Networks Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
"""BIG-IP® Global Traffic Manager (GTM) rule module.
19+
20+
REST URI
21+
``http://localhost/mgmt/tm/gtm/rule``
22+
23+
GUI Path
24+
``DNS --> GSLB : iRules``
25+
26+
REST Kind
27+
``tm:gtm:rule:*``
28+
"""
29+
30+
from f5.bigip.resource import Collection
31+
from f5.bigip.resource import Resource
32+
33+
34+
class Rules(Collection):
35+
"""BIG-IP® GTM rule collection"""
36+
def __init__(self, ltm):
37+
super(Rules, self).__init__(ltm)
38+
self._meta_data['allowed_lazy_attributes'] = [Rule]
39+
self._meta_data['attribute_registry'] =\
40+
{'tm:gtm:rule:rulestate': Rule}
41+
42+
43+
class Rule(Resource):
44+
"""BIG-IP® GTM rule resource"""
45+
def __init__(self, rule_s):
46+
super(Rule, self).__init__(rule_s)
47+
self._meta_data['required_json_kind'] = 'tm:gtm:rule:rulestate'
48+
self._meta_data['required_creation_parameters'].update(
49+
('name', 'partition', 'apiAnonymous'))

f5/bigip/tm/gtm/test/__init__.py

Whitespace-only changes.

f5/bigip/tm/gtm/test/test_rule.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2015 F5 Networks Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
import mock
17+
import pytest
18+
19+
from f5.bigip import ManagementRoot
20+
from f5.bigip.resource import MissingRequiredCreationParameter
21+
from f5.bigip.tm.gtm.rule import Rule
22+
23+
24+
@pytest.fixture
25+
def FakeRule():
26+
fake_rule_s = mock.MagicMock()
27+
fake_rule = Rule(fake_rule_s)
28+
return fake_rule
29+
30+
31+
class TestCreate(object):
32+
def test_create_two(self, fakeicontrolsession):
33+
b = ManagementRoot('192.168.1.1', 'admin', 'admin')
34+
r1 = b.tm.gtm.rules.rule
35+
r2 = b.tm.gtm.rules.rule
36+
assert r1 is not r2
37+
38+
def test_create_no_args(self, FakeRule):
39+
with pytest.raises(MissingRequiredCreationParameter):
40+
FakeRule.create()
41+
42+
def test_create_partition(self, FakeRule):
43+
with pytest.raises(MissingRequiredCreationParameter):
44+
FakeRule.create(partition='Common')
45+
46+
def test_create_name(self, FakeRule):
47+
with pytest.raises(MissingRequiredCreationParameter):
48+
FakeRule.create(name='myname')
49+
50+
def test_create_api_anon(self, FakeRule):
51+
with pytest.raises(MissingRequiredCreationParameter):
52+
FakeRule.create(apiAnonymous='when LB_SELECTED {}')

test/functional/tm/gtm/__init__.py

Whitespace-only changes.
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Copyright 2015 F5 Networks Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
#
15+
16+
import pytest
17+
18+
from f5.bigip.resource import MissingRequiredCreationParameter
19+
from f5.bigip.tm.gtm.rule import Rule
20+
from requests.exceptions import HTTPError
21+
22+
23+
RULE = '''when LB_SELECTED {
24+
set wipHost [LB::server addr]
25+
}
26+
'''
27+
28+
29+
def delete_rule(mgmt_root, name, partition):
30+
r = mgmt_root.tm.gtm.rules.rule
31+
try:
32+
r.load(name=name, partition=partition)
33+
except HTTPError as err:
34+
if err.response.status_code != 404:
35+
raise
36+
return
37+
r.delete()
38+
39+
40+
def setup_create_test(request, mgmt_root, name, partition):
41+
def teardown():
42+
delete_rule(mgmt_root, name, partition)
43+
request.addfinalizer(teardown)
44+
45+
46+
def setup_basic_test(request, mgmt_root, name, partition):
47+
def teardown():
48+
delete_rule(mgmt_root, name, partition)
49+
50+
rule1 = mgmt_root.tm.gtm.rules.rule
51+
rule1.create(name=name, partition=partition, apiAnonymous=RULE)
52+
request.addfinalizer(teardown)
53+
return rule1
54+
55+
56+
class TestCreate(object):
57+
def test_create_no_args(self, mgmt_root):
58+
rule1 = mgmt_root.tm.gtm.rules.rule
59+
with pytest.raises(MissingRequiredCreationParameter):
60+
rule1.create()
61+
62+
def test_create_no_apianonymous(self, mgmt_root):
63+
rule1 = mgmt_root.tm.gtm.rules.rule
64+
with pytest.raises(MissingRequiredCreationParameter):
65+
rule1.create(name='rule1', partition='Common')
66+
67+
def test_create(self, request, mgmt_root):
68+
setup_create_test(request, mgmt_root, 'rule1', 'Common')
69+
rule1 = mgmt_root.tm.gtm.rules.rule
70+
rule1.create(name='rule1', partition='Common', apiAnonymous=RULE)
71+
assert rule1.name == 'rule1'
72+
assert rule1.partition == 'Common'
73+
assert rule1.generation and isinstance(rule1.generation, int)
74+
assert 'LB_SELECTED' in rule1.apiAnonymous
75+
assert rule1.fullPath == '/Common/rule1'
76+
assert rule1.kind == 'tm:gtm:rule:rulestate'
77+
assert rule1.selfLink.startswith(
78+
'https://localhost/mgmt/tm/gtm/rule/~Common~rule1')
79+
80+
def test_create_optional_args(self, request, mgmt_root):
81+
setup_create_test(request, mgmt_root, 'rule1', 'Common')
82+
rule1 = mgmt_root.tm.gtm.rules.rule
83+
rule1.create(name='rule1', partition='Common',
84+
apiAnonymous=RULE,
85+
check='syntax')
86+
assert 'check syntax' in rule1.apiAnonymous
87+
88+
def test_create_duplicate(self, request, mgmt_root):
89+
setup_create_test(request, mgmt_root, 'rule1', 'Common')
90+
rule1 = mgmt_root.tm.gtm.rules.rule
91+
rule1.create(name='rule1', partition='Common',
92+
apiAnonymous=RULE,
93+
check='syntax')
94+
rule2 = mgmt_root.tm.gtm.rules.rule
95+
with pytest.raises(HTTPError) as err:
96+
rule2.create(name='rule1', partition='Common',
97+
apiAnonymous=RULE,
98+
check='syntax')
99+
assert err.response.status_code == 400
100+
101+
102+
class TestRefresh(object):
103+
def test_refresh(self, request, mgmt_root):
104+
setup_basic_test(request, mgmt_root, 'rule1', 'Common')
105+
r1 = mgmt_root.tm.gtm.rules.rule.load(
106+
name='rule1', partition='Common')
107+
r2 = mgmt_root.tm.gtm.rules.rule.load(
108+
name='rule1', partition='Common')
109+
assert 'check syntax' not in r1.apiAnonymous
110+
assert 'check syntax' not in r2.apiAnonymous
111+
112+
r2.update(apiAnonymous='check syntax\n' + RULE)
113+
assert 'check syntax' in r2.apiAnonymous
114+
assert 'check syntax' not in r1.apiAnonymous
115+
116+
r1.refresh()
117+
assert 'check syntax' in r1.apiAnonymous
118+
119+
120+
class TestLoad(object):
121+
def test_load_no_object(self, mgmt_root):
122+
with pytest.raises(HTTPError) as err:
123+
mgmt_root.tm.gtm.rules.rule.load(
124+
name='rule1', partition='Common')
125+
assert err.response.status_code == 404
126+
127+
def test_load(self, request, mgmt_root):
128+
setup_basic_test(request, mgmt_root, 'rule1', 'Common')
129+
rule1 = mgmt_root.tm.gtm.rules.rule.load(
130+
name='rule1', partition='Common')
131+
assert 'check syntax' not in rule1.apiAnonymous
132+
rule1.update(apiAnonymous='check syntax\n' + RULE)
133+
rule2 = mgmt_root.tm.gtm.rules.rule.load(
134+
name='rule1', partition='Common')
135+
assert 'check syntax' in rule1.apiAnonymous
136+
assert 'check syntax' in rule2.apiAnonymous
137+
138+
139+
class TestUpdate(object):
140+
def test_update(self, request, mgmt_root):
141+
rule1 = setup_basic_test(request, mgmt_root, 'rule1', 'Common')
142+
rule1.update(apiAnonymous='check syntax\n' + RULE)
143+
assert 'check syntax' in rule1.apiAnonymous
144+
145+
def test_update_samevalue(self, request, mgmt_root):
146+
rule1 = setup_basic_test(request, mgmt_root, 'rule1', 'Common')
147+
rule1.update(apiAnonymous='check none\n' + RULE)
148+
assert 'check syntax' not in rule1.apiAnonymous
149+
150+
151+
class TestDelete(object):
152+
def test_delete(self, request, mgmt_root):
153+
r1 = setup_basic_test(request, mgmt_root, 'rule1', 'Common')
154+
r1.delete()
155+
with pytest.raises(HTTPError) as err:
156+
mgmt_root.tm.gtm.rules.rule.load(
157+
name='rule1', partition='Common')
158+
assert err.response.status_code == 404
159+
160+
161+
class TestRuleCollection(object):
162+
def test_rule_collection(self, request, mgmt_root):
163+
setup_create_test(request, mgmt_root, 'rule1', 'Common')
164+
rule1 = mgmt_root.tm.gtm.rules.rule
165+
rule1.create(name='rule1', partition='Common', apiAnonymous=RULE)
166+
assert rule1.name == 'rule1'
167+
assert rule1.partition == 'Common'
168+
assert rule1.generation and isinstance(rule1.generation, int)
169+
assert 'LB_SELECTED' in rule1.apiAnonymous
170+
assert rule1.fullPath == '/Common/rule1'
171+
assert rule1.kind == 'tm:gtm:rule:rulestate'
172+
assert rule1.selfLink.startswith(
173+
'https://localhost/mgmt/tm/gtm/rule/~Common~rule1')
174+
175+
rc = mgmt_root.tm.gtm.rules.get_collection()
176+
assert isinstance(rc, list)
177+
assert len(rc)
178+
assert isinstance(rc[0], Rule)

0 commit comments

Comments
 (0)