Repository: F5Networks/f5-common-python

Issue:
factor other supported parameters and formats into iapp_parser
The iapp_parser util supports the common formats for iapps but does not support all of them, particularly those that are part of the iapp templates that F5 releases on downloads.f5.com

Discussion:
wojtek0806: @pjbreaux or @caphrim007 whenever it finishes testing please merge :)

Patch:
diff --git a/f5/bigip/resource.py b/f5/bigip/resource.py
index 3bfcfec..018bfe1 100644
--- a/f5/bigip/resource.py
+++ b/f5/bigip/resource.py
@@ -100,6 +100,7 @@ from f5.bigip.mixins import LazyAttributeMixin
 from f5.bigip.mixins import ToDictMixin
 from f5.sdk_exception import F5SDKError
 from f5.sdk_exception import UnsupportedMethod
+from icontrol.exceptions import iControlUnexpectedHTTPError
 from requests.exceptions import HTTPError
 from six import iteritems
 from six import iterkeys
@@ -508,9 +509,18 @@ class ResourceBase(PathElement, ToDictMixin):
 
         data_dict.update(kwargs)
 
-        response = session.put(update_uri, json=data_dict, **requests_params)
-        self._meta_data = temp_meta
-        self._local_update(response.json())
+        # This is necessary as when we receive exception the returned object
+        # has its _meta_data stripped.
+
+        try:
+            response = session.put(update_uri, json=data_dict,
+                                   **requests_params)
+        except iControlUnexpectedHTTPError:
+                response = session.get(update_uri, **requests_params)
+                raise
+        finally:
+            self._meta_data = temp_meta
+            self._local_update(response.json())
 
     def update(self, **kwargs):
         """Update the configuration of the resource on the BIG-IP®.


Test patch:
diff --git a/f5/bigip/test/unit/test_resource.py b/f5/bigip/test/unit/test_resource.py
index ed022d9..3ef0de4 100644
--- a/f5/bigip/test/unit/test_resource.py
+++ b/f5/bigip/test/unit/test_resource.py
@@ -47,6 +47,7 @@ from f5.bigip.tm.ltm.virtual import Policies_s
 from f5.bigip.tm.ltm.virtual import Profiles_s
 from f5.bigip.tm.ltm.virtual import Virtual
 from f5.sdk_exception import UnsupportedMethod
+from icontrol.exceptions import iControlUnexpectedHTTPError
 
 
 @pytest.fixture
@@ -330,6 +331,30 @@ class TestResource_update(object):
         assert pre_meta == r._meta_data
         assert r.raw == r.__dict__
 
+    def test_meta_data_exception_raised(self):
+        r = Resource(mock.MagicMock())
+        fake_session = mock.MagicMock(name='mock_session')
+        r._meta_data['allowed_lazy_attributes'] = []
+        r._meta_data['uri'] = 'URI'
+        text = 'Unexpected Error: Bad Request for uri: URI'
+        error_response = mock.MagicMock(name='error_mock')
+        error_response.status_code = 400
+        error_response.text = text
+        error = iControlUnexpectedHTTPError(response=error_response)
+        fake_session.get.return_value = MockResponse({u"generation": 0})
+        fake_session.put.side_effect = error
+        r._meta_data['bigip']._meta_data = {'icr_session': fake_session,
+                                            'hostname': 'TESTDOMAINNAME',
+                                            'uri':
+                                            'https://TESTDOMAIN:443/mgmt/tm/'}
+        pre_meta = r._meta_data.copy()
+        with pytest.raises(iControlUnexpectedHTTPError) as err:
+            r.update(a=u"b")
+        assert err.value.response.status_code == 400
+        assert err.value.response.text == text
+        assert pre_meta == r._meta_data
+        assert r.raw == r.__dict__
+
     def test_Collection_removal(self):
         r = Resource(mock.MagicMock())
         r._meta_data['allowed_lazy_attributes'] = []