Repository: F5Networks/f5-icontrol-rest-python

Issue:
support rest-proxy URI
iWorkflow / BIG-IQ (?) support REST proxy URI.  This makes it possible to apply tenant RBAC on the REST endpoints (i.e. limit a user to only be able to modify a single BIG-IP LTM pool in a single Partition).

Documented here: https://devcentral.f5.com/wiki/iControl.REST_proxy_APIs.ashx

Example of one of the changes required (this is not meant to be a "good" example, but it gets the job done).  This was done to monkey patch the library:

```
def _validate_icruri(base_uri):
    # The icr_uri should specify https, the server name/address, and the path
    # to the REST-or-tm management interface "/mgmt/tm/"
    scheme, netloc, path, _, _ = urlsplit(base_uri)
    if scheme != 'https':
        raise InvalidScheme(scheme)
    if path.startswith('/mgmt/shared/'):
        return icontrol.session._validate_prefix_collections(path[9:])
    if not path.startswith('/mgmt/tm/'):
        error_message = "The path must start with '/mgmt/tm/'!!  But it's:" +\
            " '%s'" % path[:10]
        raise InvalidBigIP_ICRURI(error_message)
    return icontrol.session._validate_prefix_collections(path[9:])
icontrol.session._validate_icruri = _validate_icruri

```


Comments:

Patch:
diff --git a/icontrol/session.py b/icontrol/session.py
index 376541f..d05ec3f 100644
--- a/icontrol/session.py
+++ b/icontrol/session.py
@@ -86,11 +86,22 @@ def _validate_icruri(base_uri):
     scheme, netloc, path, _, _ = urlsplit(base_uri)
     if scheme != 'https':
         raise InvalidScheme(scheme)
-    if not path.startswith('/mgmt/tm/'):
-        error_message = "The path must start with '/mgmt/tm/'!!  But it's:" +\
-            " '%s'" % path[:10]
+
+    if path.startswith('/mgmt/tm/'):
+        # Most of the time this is BIG-IP
+        sub_path = path[9:]
+    elif path.startswith('/mgmt/cm/'):
+        # This can also be in iWorkflow or BIG-IQ
+        sub_path = path[9:]
+    elif path.startswith('/mgmt/shared/'):
+        # This can be iWorkflow or BIG-IQ
+        sub_path = path[13:]
+    else:
+        error_message = "The path must start with either '/mgmt/tm/'," \
+                        "'/mgmt/cm/', or '/mgmt/shared/'!  But it's:" \
+                        " '%s'" % path
         raise InvalidBigIP_ICRURI(error_message)
-    return _validate_prefix_collections(path[9:])
+    return _validate_prefix_collections(sub_path)
 
 
 def _validate_prefix_collections(prefix_collections):


Test patch:
diff --git a/icontrol/test/unit/test_session.py b/icontrol/test/unit/test_session.py
index 240505c..9742ae4 100644
--- a/icontrol/test/unit/test_session.py
+++ b/icontrol/test/unit/test_session.py
@@ -55,6 +55,26 @@ def uparts_with_subpath():
     return parts_dict
 
 
+@pytest.fixture()
+def uparts_shared():
+    parts_dict = {'base_uri': 'https://0.0.0.0/mgmt/shared/root/RESTiface/',
+                  'partition': 'BIGCUSTOMER',
+                  'name': 'foobar1',
+                  'sub_path': '',
+                  'suffix': '/members/m1'}
+    return parts_dict
+
+
+@pytest.fixture()
+def uparts_cm():
+    parts_dict = {'base_uri': 'https://0.0.0.0/mgmt/cm/root/RESTiface/',
+                  'partition': 'BIGCUSTOMER',
+                  'name': 'foobar1',
+                  'sub_path': '',
+                  'suffix': '/members/m1'}
+    return parts_dict
+
+
 # Test invalid args
 def test_iCRS_with_invalid_construction():
     with pytest.raises(TypeError) as UTE:
@@ -74,8 +94,7 @@ def test_incorrect_uri_construction_bad_mgmt_path(uparts):
     uparts['base_uri'] = 'https://0.0.0.0/magmt/tm/root/RESTiface'
     with pytest.raises(session.InvalidBigIP_ICRURI) as IR:
         session.generate_bigip_uri(**uparts)
-    assert str(IR.value) ==\
-        "The path must start with '/mgmt/tm/'!!  But it's: '/magmt/tm/'"
+    assert "But it's: '/magmt/tm/root/RESTiface'" in str(IR.value)
 
 
 def test_incorrect_uri_construction_bad_base_nonslash_last(uparts):
@@ -220,6 +239,20 @@ def test_correct_uri_construction_nameless_and_suffixless_subpath(
     assert uri == 'https://0.0.0.0/mgmt/tm/root/RESTiface/~BIGCUSTOMER~sp'
 
 
+def test_correct_uri_construction_mgmt_shared(uparts_shared):
+    uparts_shared['name'] = ''
+    uparts_shared['suffix'] = ''
+    uri = session.generate_bigip_uri(**uparts_shared)
+    assert uri == 'https://0.0.0.0/mgmt/shared/root/RESTiface/~BIGCUSTOMER'
+
+
+def test_correct_uri_construction_mgmt_cm(uparts_cm):
+    uparts_cm['name'] = ''
+    uparts_cm['suffix'] = ''
+    uri = session.generate_bigip_uri(**uparts_cm)
+    assert uri == 'https://0.0.0.0/mgmt/cm/root/RESTiface/~BIGCUSTOMER'
+
+
 # Test exception handling
 def test_wrapped_delete_success(iCRS, uparts):
     iCRS.delete(uparts['base_uri'], partition='AFN', name='AIN',