Skip to content

Commit 6df9c8d

Browse files
authored
Merge pull request #625 from F5Networks/ucs_support2
2 parents dfc8f76 + c35ad97 commit 6df9c8d

7 files changed

Lines changed: 278 additions & 4 deletions

File tree

conftest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,49 @@ def pytest_addoption(parser):
4949
@pytest.fixture
5050
def fakeicontrolsession(monkeypatch):
5151
class Response(object):
52+
5253
def json(self):
5354
return {'selfLink': 'https://localhost/mgmt/tm/sys?ver=11.6.0'}
55+
56+
fakesessionclass = mock.create_autospec(iControlRESTSession, spec_set=True)
57+
fakesessioninstance = mock.create_autospec(iControlRESTSession('A', 'B'),
58+
spec_set=True)
59+
fakesessioninstance.get =\
60+
mock.MagicMock(return_value=Response())
61+
fakesessionclass.return_value = fakesessioninstance
62+
monkeypatch.setattr('f5.bigip.iControlRESTSession', fakesessionclass)
63+
64+
65+
@pytest.fixture
66+
def fakeicontrolsessionfactory(monkeypatch):
67+
class Response(object):
68+
def __init__(self, **json_keys):
69+
if 'selfLink' not in json_keys:
70+
json_keys['selfLink'] =\
71+
'https://localhost/mgmt/tm/sys?ver=11.6.0'
72+
self.params = json_keys
73+
74+
def json(self):
75+
return self.params
76+
77+
def _session_factory(**json_keys):
78+
fakesessionclass = mock.create_autospec(iControlRESTSession,
79+
spec_set=True)
80+
fakesessioninstance =\
81+
mock.create_autospec(iControlRESTSession('A', 'B'), spec_set=True)
82+
fakesessioninstance.get =\
83+
mock.MagicMock(return_value=Response(**json_keys))
84+
fakesessionclass.return_value = fakesessioninstance
85+
monkeypatch.setattr('f5.bigip.iControlRESTSession', fakesessionclass)
86+
87+
return _session_factory
88+
89+
90+
@pytest.fixture
91+
def fakeicontrolsession_v12(monkeypatch):
92+
class Response(object):
93+
def json(self):
94+
return {'selfLink': 'https://localhost/mgmt/tm/sys?ver=12.1.0'}
5495
fakesessionclass = mock.create_autospec(iControlRESTSession, spec_set=True)
5596
fakesessioninstance =\
5697
mock.create_autospec(iControlRESTSession('A', 'B'), spec_set=True)

f5/bigip/cm/autodeploy/test/test_software_image_uploads.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
CHUNKSIZE = 20
2525

2626

27-
def test_software_image_uploads_80a(tmpdir, fakeicontrolsession):
27+
def test_software_image_uploads_80a(tmpdir, fakeicontrolsessionfactory):
28+
fakeicontrolsessionfactory()
2829
filepath = tmpdir.mkdir('testdir').join('eightya.iso')
2930
filepath.write(80*'a')
3031
mr = ManagementRoot('FAKENETLOC', 'FAKENAME', 'FAKEPASSWORD')
@@ -37,7 +38,8 @@ def test_software_image_uploads_80a(tmpdir, fakeicontrolsession):
3738
assert d == 'a'*CHUNKSIZE
3839

3940

40-
def test_software_image_uploads_70a(tmpdir, fakeicontrolsession):
41+
def test_software_image_uploads_70a(tmpdir, fakeicontrolsessionfactory):
42+
fakeicontrolsessionfactory()
4143
filepath = tmpdir.mkdir('testdir').join('seventya.iso')
4244
filepath.write(70*'a')
4345
mr = ManagementRoot('FAKENETLOC', 'FAKENAME', 'FAKEPASSWORD')
@@ -53,7 +55,8 @@ def test_software_image_uploads_70a(tmpdir, fakeicontrolsession):
5355
assert 10*'a' == lchunk
5456

5557

56-
def test_non_ISO_extension(tmpdir, fakeicontrolsession):
58+
def test_non_ISO_extension(tmpdir, fakeicontrolsessionfactory):
59+
fakeicontrolsessionfactory()
5760
filepath = tmpdir.mkdir('testdir').join('wrong.name')
5861
mr = ManagementRoot('FAKENETLOC', 'FAKENAME', 'FAKEPASSWORD')
5962
sius = mr.cm.autodeploy.software_image_uploads

f5/bigip/mixins.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,24 @@ def _check_supported_versions(self, container, attribute):
126126
minimum)
127127
raise UnsupportedTmosVersion(error)
128128

129+
def _is_version_supported_method(container, method_version):
130+
"""Helper method
131+
132+
To use in instances where class methods on some resources
133+
require a specific TMOS version to run.
134+
135+
Raises::
136+
UnsupportedTmosVersion
137+
"""
138+
tmos_v = container._meta_data['bigip'].tmos_version
139+
if LooseVersion(tmos_v) < LooseVersion(method_version):
140+
error = "There was an attempt to use a method which " \
141+
"has not been implemented or supported " \
142+
"in the device's TMOS version: %s. " \
143+
"Minimum TMOS version supported is %s" % (
144+
tmos_v, method_version)
145+
raise UnsupportedTmosVersion(error)
146+
129147

130148
class ExclusiveAttributesMixin(object):
131149
"""Overrides ``__setattr__`` to remove exclusive attrs from the object."""

f5/bigip/tm/sys/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from f5.bigip.tm.sys.performance import Performances
4343
from f5.bigip.tm.sys.software import Software
4444
from f5.bigip.tm.sys.sshd import Sshd
45+
from f5.bigip.tm.sys.ucs import Ucs
4546

4647

4748
class Sys(OrganizingCollection):
@@ -61,5 +62,6 @@ def __init__(self, tm):
6162
Dns,
6263
Sshd,
6364
Httpd,
64-
Software
65+
Software,
66+
Ucs
6567
]

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# coding=utf-8
2+
#
3+
# Copyright 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+
19+
import mock
20+
import pytest
21+
22+
from f5.bigip import ManagementRoot
23+
from f5.bigip.mixins import UnsupportedTmosVersion
24+
from f5.bigip.tm.sys.ucs import Ucs
25+
26+
27+
@pytest.fixture
28+
def FakeUcs():
29+
fake_sys = mock.MagicMock()
30+
fake_ucs = Ucs(fake_sys)
31+
fake_ucs._meta_data['bigip'].tmos_version = '12.0.0'
32+
return fake_ucs
33+
34+
35+
@pytest.fixture
36+
def FakeiControl(fakeicontrolsession_v12):
37+
mr = ManagementRoot('FAKENETLOC', 'FAKENAME', 'FAKEPASSWORD')
38+
mock_session = mock.MagicMock()
39+
mock_session.post.return_value.json.return_value = {}
40+
mr._meta_data['icr_session'] = mock_session
41+
return mr.tm.sys.ucs
42+
43+
44+
class TestUCSCommand(object):
45+
def test_command_ucs_load(self, FakeiControl):
46+
FakeiControl.exec_cmd('load', name='foo.ucs')
47+
session = FakeiControl._meta_data['bigip']._meta_data['icr_session']
48+
assert session.post.call_args == mock.call(
49+
'https://FAKENETLOC:443/mgmt/tm/sys/ucs/',
50+
json={'name': 'foo.ucs', 'command': 'load'}
51+
)
52+
53+
def test_command_ucs_save(self, FakeiControl):
54+
FakeiControl.exec_cmd('save', name='foo.ucs')
55+
session = FakeiControl._meta_data['bigip']._meta_data['icr_session']
56+
assert session.post.call_args == mock.call(
57+
'https://FAKENETLOC:443/mgmt/tm/sys/ucs/',
58+
json={'name': 'foo.ucs', 'command': 'save'}
59+
)
60+
61+
def test_list_ucs_wrong_tmos_version(self, FakeUcs):
62+
with pytest.raises(UnsupportedTmosVersion) as EIO:
63+
FakeUcs.load()
64+
assert EIO.value.message == \
65+
"There was an attempt to use a method which " \
66+
"has not been implemented or supported " \
67+
"in the device's TMOS version: 12.0.0. " \
68+
"Minimum TMOS version supported is 12.1.0"

f5/bigip/tm/sys/ucs.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# coding=utf-8
2+
#
3+
# Copyright 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+
"""BIG-IP® system config module
18+
19+
REST URI
20+
``http://localhost/mgmt/tm/sys/ucs`
21+
22+
GUI Path
23+
N/A
24+
25+
REST Kind
26+
``tm:sys:ucs:*``
27+
"""
28+
29+
from f5.bigip.mixins import CommandExecutionMixin
30+
from f5.bigip.mixins import InvalidCommand
31+
from f5.bigip.resource import UnnamedResource
32+
from requests.exceptions import HTTPError
33+
34+
35+
class Ucs(UnnamedResource, CommandExecutionMixin):
36+
"""BIG-IP® system UCS resource
37+
38+
.. note::
39+
Given the fact that 11.6.0 UCS via rest is
40+
broken, this feature will be supported in 12.0.0 and above.
41+
Listing of installed UCS has been fixed in 12.1.0.
42+
This resource is a collection which does not allow listing
43+
of each ucs as a resource. 'Items' attribute of the loaded object
44+
is used to access the list of installed UCS files.
45+
46+
Caveat:
47+
Loading UCS will result in ICRD restarting, therefore
48+
due to ID476518 502 Bad Gateway is generated, this is
49+
working as intended, at least until some architecture
50+
changes have been made.
51+
52+
53+
"""
54+
def __init__(self, sys):
55+
super(Ucs, self).__init__(sys)
56+
self._meta_data['required_load_parameters'] = set()
57+
self._meta_data['allowed_commands'].extend(['load', 'save'])
58+
self._meta_data['required_json_kind'] = ''
59+
self._meta_data['minimum_version'] = '12.0.0'
60+
61+
def exec_cmd(self, command, **kwargs):
62+
"""Due to ID476518 the load command need special treatment"""
63+
cmds = self._meta_data['allowed_commands']
64+
65+
if command not in self._meta_data['allowed_commands']:
66+
error_message = "The command value {0} does not exist" \
67+
"Valid commands are {1}".format(command, cmds)
68+
raise InvalidCommand(error_message)
69+
70+
if command == 'load':
71+
kwargs['command'] = command
72+
self._check_exclusive_parameters(**kwargs)
73+
requests_params = self._handle_requests_params(kwargs)
74+
self._check_command_parameters(**kwargs)
75+
session = self._meta_data['bigip']._meta_data['icr_session']
76+
try:
77+
78+
session.post(
79+
self._meta_data['uri'], json=kwargs, **requests_params)
80+
81+
except HTTPError as err:
82+
if err.response.status_code != 502:
83+
raise
84+
return
85+
86+
else:
87+
return self._exec_cmd(command, **kwargs)
88+
89+
def load(self, **kwargs):
90+
"""Method to list the UCS on the system
91+
92+
Since this is only fixed in 12.1.0 and up
93+
we implemented version check here
94+
"""
95+
96+
# Check if we are using 12.1.0 version or above when using this method
97+
self._is_version_supported_method('12.1.0')
98+
newinst = self._stamp_out_core()
99+
newinst._refresh(**kwargs)
100+
101+
return newinst

test/functional/tm/sys/test_ucs.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2015-2016 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+
from f5.bigip.mixins import LazyAttributesRequired
17+
import pytest
18+
import time
19+
20+
21+
@pytest.mark.skipif(pytest.config.getoption('--release') != '12.1.0',
22+
reason='Needs v12.1 TMOS to pass')
23+
class TestUcs(object):
24+
def test_ucs_LR(self, bigip):
25+
f = bigip.sys.ucs.load()
26+
27+
# Just in case our test unit does not have any ucs we create one
28+
try:
29+
f.items
30+
except LazyAttributesRequired:
31+
bigip.sys.ucs.exec_cmd('save', name='dummyucs.ucs')
32+
time.sleep(1)
33+
f.refresh()
34+
finally:
35+
ucs1 = len(f.items)
36+
assert ucs1 >= 0
37+
bigip.sys.ucs.exec_cmd('save', name='foobar.ucs')
38+
time.sleep(1)
39+
f.refresh()
40+
ucs2 = len(f.items)
41+
assert ucs2 > ucs1

0 commit comments

Comments
 (0)