Skip to content

Commit 76f41b7

Browse files
author
pjbreaux
authored
Merge pull request #627 from zancas/feature.stats_293
Feature.stats 293
2 parents 6df9c8d + 63f2554 commit 76f41b7

8 files changed

Lines changed: 98 additions & 47 deletions

File tree

f5/bigip/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,6 @@ def hostname(self):
7171
def icontrol_version(self):
7272
return self._meta_data['icontrol_version']
7373

74-
@property
75-
def tmos_version(self):
76-
return self._meta_data['tmos_version']
77-
7874
def _get_tmos_version(self):
7975
connect = self._meta_data['bigip']._meta_data['icr_session']
8076
base_uri = self._meta_data['uri'] + 'tm/sys/'

f5/bigip/mixins.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def __getattr__(container, name):
114114
return attribute
115115

116116
def _check_supported_versions(self, container, attribute):
117-
tmos_v = container._meta_data['bigip'].tmos_version
117+
tmos_v = container._meta_data['bigip']._meta_data['tmos_version']
118118
minimum = attribute._meta_data['minimum_version']
119119
if LooseVersion(tmos_v) < LooseVersion(minimum):
120120
error = "There was an attempt to access resource: \n{}\n which " \

f5/bigip/resource.py

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -364,22 +364,6 @@ class ResourceBase(PathElement, ToDictMixin):
364364
that represents objects in a hierarchical relationship similar to the
365365
device's uri path hierarchy.
366366
"""
367-
def __init__(self, container):
368-
"""Call this with containing_object_instance.FOO
369-
370-
Where FOO is a concrete subclass of this class, ResourceBase. The '.'
371-
operator passes "FOO" to the __getattr__ method of the
372-
containing_object_instance which instantiates it as the appropriate
373-
sub-type of ResourceBase.
374-
375-
Since all ResourceBases sub-types must support the `refresh` method, it
376-
is defined here, in the base class.
377-
NOTE: The BIG-IP® uri 'mgmt/tm/' uniquely passes itself to this
378-
constructor as the "container".
379-
380-
:param container: instance is an attribute of a ResourceBase container
381-
"""
382-
super(ResourceBase, self).__init__(container)
383367

384368
def _modify(self, **patch):
385369
"""Wrapped with modify, override in a subclass to customize."""
@@ -634,12 +618,6 @@ class OrganizingCollection(ResourceBase):
634618
* provide a list of dictionaries that contain uri's to other
635619
resources on the device.
636620
"""
637-
def __init__(self, container):
638-
"""Call this to construct an OC. It should be an attribute of BIG-IP®.
639-
640-
:param bigip: all OCs are attributes of a BIG-IP® instance
641-
"""
642-
super(OrganizingCollection, self).__init__(container)
643621

644622
def get_collection(self, **kwargs):
645623
"""Call to obtain a list of the reference dicts in the instance `items`
@@ -665,20 +643,6 @@ class Collection(ResourceBase):
665643
unless it ends in ``s`` then it must have ``_s``.
666644
667645
"""
668-
def __init__(self, container):
669-
"""Call this with the __get_attr__ of a Resource or OC.
670-
671-
The contained-by-an-OC-or-Resource pattern is observed, and not a
672-
strictly enforced part of the model.
673-
674-
URIs are constructed _from_ Collection subclass names. All Collection
675-
subclass names MUST end in 's' or '_s', to distinguish them from their
676-
associated Resource (which is always accessible as an attribute of the
677-
subclass instance.
678-
679-
:param container: instances of Collection are attributes of container
680-
"""
681-
super(Collection, self).__init__(container)
682646

683647
def get_collection(self, **kwargs):
684648
"""Get an iterator of Python ``Resource`` objects that represent URIs.
@@ -807,6 +771,7 @@ def _activate_URI(self, selfLinkuri):
807771
# attrs local alias
808772
attribute_reg = self._meta_data.get('attribute_registry', {})
809773
attrs = attribute_reg.values()
774+
attrs.append(Stats)
810775

811776
(scheme, domain, path, qarg, frag) = urlparse.urlsplit(selfLinkuri)
812777
path_uri = urlparse.urlunsplit((scheme, uri.netloc, path, '', ''))
@@ -1035,3 +1000,20 @@ def load(self, **kwargs):
10351000
newinst = self._stamp_out_core()
10361001
newinst._refresh(**kwargs)
10371002
return newinst
1003+
1004+
1005+
class Stats(UnnamedResource):
1006+
'''For stats resources.'''
1007+
1008+
def modify(self, **kwargs):
1009+
'''Modify is not supported for unnamed resources
1010+
1011+
:raises: UnsupportedOperation
1012+
'''
1013+
raise UnsupportedMethod(
1014+
"%s does not support the modify method" % self.__class__.__name__
1015+
)
1016+
1017+
def load(self, **kwargs):
1018+
# TODO(pjbreaux) add try-except and custom exception here.
1019+
return super(Stats, self).load(**kwargs)

f5/bigip/test/test_resource.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
from f5.bigip.resource import RequestParamKwargCollision
3535
from f5.bigip.resource import Resource
3636
from f5.bigip.resource import ResourceBase
37+
from f5.bigip.resource import Stats
3738
from f5.bigip.resource import UnnamedResource
3839
from f5.bigip.resource import UnregisteredKind
3940
from f5.bigip.resource import URICreationCollision
4041
from f5.bigip.tm.cm.sync_status import Sync_Status
42+
from f5.bigip.tm.ltm.virtual import Profiles_s
4143
from f5.bigip.tm.ltm.virtual import Virtual
4244
from f5.sdk_exception import UnsupportedMethod
4345

@@ -99,8 +101,8 @@ def test_Resource__local_update_IncompatibleKeys():
99101
" it's not a valid Python 2.7 identifier."
100102

101103

102-
def test_Resource__local_update():
103-
r = Resource(mock.MagicMock())
104+
def test_Resource__local_update(fake_vs):
105+
r = fake_vs
104106
stash = r._meta_data.copy()
105107
r._local_update({'test': 1})
106108
assert stash == r._meta_data
@@ -207,7 +209,7 @@ def test__activate_URI():
207209
assert r._meta_data['creation_uri_qargs'] ==\
208210
{'a': ['b'], 'ver': ['11.5']}
209211
assert r._meta_data['creation_uri_frag'] == 'FOO'
210-
assert r._meta_data['allowed_lazy_attributes'] == [u"SPAM"]
212+
assert r._meta_data['allowed_lazy_attributes'] == [u"SPAM", Stats]
211213

212214

213215
def test__create_with_Collision():
@@ -757,3 +759,57 @@ def test_load(self):
757759
r.generation = 0
758760
x = r.load(partition='Common', name='test_load')
759761
assert x.selfLink == 'https://localhost:443/mgmt/tm/cm/sync-status'
762+
763+
764+
class TestStats(object):
765+
def test_create_raises(self):
766+
stats_resource = Stats(mock.MagicMock())
767+
with pytest.raises(UnsupportedMethod):
768+
stats_resource.create()
769+
770+
def test_delete_raises(self):
771+
stats_resource = Stats(mock.MagicMock())
772+
with pytest.raises(UnsupportedMethod):
773+
stats_resource.delete()
774+
775+
def test_modify_raises(self):
776+
stats_resource = Stats(mock.MagicMock())
777+
with pytest.raises(UnsupportedMethod):
778+
stats_resource.modify()
779+
780+
def test_load(self):
781+
r = Virtual(mock.MagicMock())
782+
r._meta_data['allowed_lazy_attributes'] = []
783+
attrs = {'get.side_effect':
784+
[MockResponse(
785+
{
786+
u"generation": 0,
787+
u"selfLink": "https://localhost:443/mgmt/tm/ltm/"
788+
"virtual",
789+
u"kind": u"tm:ltm:virtual:virtualstate"
790+
}),
791+
MockResponse(
792+
{
793+
u"generation": 0,
794+
u"selfLink": u'https://localhost/mgmt/tm/ltm/virtual/'
795+
'~Common~modtest1/stats?ver=11.6.0',
796+
u"kind": u"tm:ltm:virtual:virtualstats"
797+
})
798+
]}
799+
mock_session = mock.MagicMock(**attrs)
800+
r._meta_data['bigip']._meta_data =\
801+
{'icr_session': mock_session,
802+
'hostname': 'TESTDOMAINNAME',
803+
'uri': 'https://TESTDOMAIN:443/mgmt/tm/',
804+
'tmos_version': '11.5.0',
805+
'minimum_version': '11.5.0'}
806+
r.generation = 0
807+
x = r.load(partition='Common', name='test_load')
808+
assert x.selfLink == 'https://localhost:443/mgmt/tm/ltm/virtual'
809+
assert x._meta_data['allowed_lazy_attributes'] == [Profiles_s, Stats]
810+
statsfactory = x.stats
811+
assert 'selfLink' not in statsfactory.__dict__
812+
statsobj = statsfactory.load()
813+
assert statsobj.selfLink ==\
814+
u'https://localhost/mgmt/tm/ltm/virtual/'\
815+
'~Common~modtest1/stats?ver=11.6.0'

f5/bigip/tm/sys/test/test_db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
def fake_dbs():
2424
fake_sys = mock.MagicMock()
2525
dbs = Dbs(fake_sys)
26-
dbs._meta_data['bigip'].tmos_version = '11.6.0'
26+
dbs._meta_data['bigip']._meta_data = {'tmos_version': '11.6.0'}
2727
return dbs
2828

2929

f5/bigip/tm/sys/test/test_folder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
def FakeFolders():
2525
fake_sys = mock.MagicMock()
2626
folders = Folders(fake_sys)
27-
folders._meta_data['bigip'].tmos_version = '11.6.0'
27+
folders._meta_data['bigip']._meta_data = {'tmos_version': '11.6.0'}
2828
return folders
2929

3030

f5/bigip/tm/sys/test/test_performance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
def FakePerformance():
2626
fake_sys = mock.MagicMock()
2727
performances = Performances(fake_sys)
28-
performances._meta_data['bigip'].tmos_version = '11.6.0'
28+
performances._meta_data['bigip']._meta_data = {'tmos_version': '11.6.0'}
2929
return performances
3030

3131

test/functional/tm/ltm/test_virtual.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from f5.bigip.resource import MissingRequiredCreationParameter
1919
from f5.bigip.resource import MissingRequiredReadParameter
20+
from f5.sdk_exception import UnsupportedMethod
2021

2122
import copy
2223
from pprint import pprint as pp
@@ -77,6 +78,22 @@ def test_virtual_modify(self, request, mgmt_root, setup_device_snapshot):
7778
elif k == desc:
7879
virtual1.__dict__[k] == 'Cool mod test'
7980

81+
def test_stats(self, request, mgmt_root, setup_device_snapshot):
82+
virtual1, vc1 = setup_virtual_test(
83+
request, mgmt_root, 'Common', 'modtest1'
84+
)
85+
stats = virtual1.stats.load()
86+
pp(stats.raw)
87+
assert virtual1.cmpEnabled == u'yes'
88+
assert stats.entries['cmpEnabled']['description'] == u'enabled'
89+
virtual1.modify(cmpEnabled=u'no')
90+
stats.refresh()
91+
assert stats.entries['cmpEnabled']['description'] == u'disabled'
92+
with pytest.raises(UnsupportedMethod) as USMEIO:
93+
stats.modify(description='foo')
94+
assert USMEIO.value.message ==\
95+
"Stats does not support the modify method"
96+
8097

8198
def test_profiles_CE(
8299
mgmt_root, opt_release, setup_device_snapshot

0 commit comments

Comments
 (0)