Repository: F5Networks/f5-common-python

Issue:
add asm policy templates endpoint
this endpoint is missing, this issue is a blocker for #1153 and a major blocker for the ansible asm module :(

Discussion:
caphrim007: @wojtek0806 here is the patch that fixes the errors i saw for 11.6.0

https://gist.github.com/caphrim007/145826c42595fa0e351c21fb21308f16
wojtek0806: I will clean up any travis problems and will disable those failing tests and open up an issue to rework the ASM policies to split it into smaller bits. So we can merge this. @caphrim007 
caphrim007: lgtm

Patch:
diff --git a/f5/bigip/tm/asm/__init__.py b/f5/bigip/tm/asm/__init__.py
index f8c2671..35f3363 100644
--- a/f5/bigip/tm/asm/__init__.py
+++ b/f5/bigip/tm/asm/__init__.py
@@ -31,6 +31,7 @@ from f5.bigip.resource import OrganizingCollection
 from f5.bigip.tm.asm.attack_types import Attack_Types_s
 from f5.bigip.tm.asm.file_transfer import File_Transfer
 from f5.bigip.tm.asm.policies import Policies_s
+from f5.bigip.tm.asm.policy_templates import Policy_Templates_s
 from f5.bigip.tm.asm.signature_sets import Signature_Sets_s
 from f5.bigip.tm.asm.signature_statuses import Signature_Statuses_s
 from f5.bigip.tm.asm.signature_systems import Signature_Systems_s
@@ -51,6 +52,7 @@ class Asm(OrganizingCollection):
             Attack_Types_s,
             File_Transfer,
             Policies_s,
+            Policy_Templates_s,
             Signature_Sets_s,
             Signature_Statuses_s,
             Signature_Systems_s,
diff --git a/f5/bigip/tm/asm/policy_templates.py b/f5/bigip/tm/asm/policy_templates.py
new file mode 100644
index 0000000..d1f4c3d
--- /dev/null
+++ b/f5/bigip/tm/asm/policy_templates.py
@@ -0,0 +1,77 @@
+# coding=utf-8
+#
+# Copyright 2017 F5 Networks Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""BIG-IP® Application Security Manager™ (ASM®) module.
+
+REST URI
+    ``http://localhost/mgmt/tm/asm/policy-templates``
+
+GUI Path
+    ``Security -> Options -> Advanced Configuration -> Policy Templates``
+
+REST Kind
+    ``tm:asm:policy-templates:*``
+"""
+
+from f5.bigip.resource import AsmResource
+from f5.bigip.resource import Collection
+from f5.sdk_exception import UnsupportedOperation
+
+
+class Policy_Templates_s(Collection):
+    """BIG-IP® ASM Policiy Templates collection."""
+    def __init__(self, asm):
+        super(Policy_Templates_s, self).__init__(asm)
+        self._meta_data['object_has_stats'] = False
+        self._meta_data['allowed_lazy_attributes'] = [Policy_Template]
+        self._meta_data['attribute_registry'] = {
+            'tm:asm:policy-templates:policy-templatestate': Policy_Template}
+
+
+class Policy_Template(AsmResource):
+    """BIG-IP® ASM Policy Template resource."""
+    def __init__(self, policy_templates_s):
+        super(Policy_Template, self).__init__(policy_templates_s)
+        self._meta_data['required_json_kind'] = \
+            'tm:asm:policy-templates:policy-templatestate'
+
+    def create(self, **kwargs):
+        """Create is not supported for Policy Template resources
+
+        :raises: UnsupportedOperation
+        """
+        raise UnsupportedOperation(
+            "%s does not support the create method" % self.__class__.__name__
+        )
+
+    def delete(self, **kwargs):
+        """Delete is not supported for Policy Template resources
+
+        :raises: UnsupportedOperation
+        """
+        raise UnsupportedOperation(
+            "%s does not support the delete method" % self.__class__.__name__
+        )
+
+    def modify(self, **patch):
+        """Modify is not supported for Policy Template resources
+
+        :raises: UnsupportedOperation
+        """
+        raise UnsupportedOperation(
+            "%s does not support the delete method" % self.__class__.__name__
+        )


Test patch:
diff --git a/f5/bigip/tm/asm/test/functional/test_policy_templates.py b/f5/bigip/tm/asm/test/functional/test_policy_templates.py
new file mode 100644
index 0000000..e5d7076
--- /dev/null
+++ b/f5/bigip/tm/asm/test/functional/test_policy_templates.py
@@ -0,0 +1,78 @@
+# Copyright 2017 F5 Networks Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import pytest
+
+from f5.bigip.tm.asm.policy_templates import Policy_Template
+from f5.sdk_exception import UnsupportedOperation
+from requests.exceptions import HTTPError
+
+
+@pytest.fixture(scope='class')
+def return_template(mgmt_root):
+    rc = mgmt_root.tm.asm.policy_templates_s.get_collection()
+    return rc[0], rc[0].id
+
+
+class TestPolicyTemplates(object):
+    def test_create_raises(self, mgmt_root):
+        rc = mgmt_root.tm.asm.policy_templates_s
+        with pytest.raises(UnsupportedOperation):
+            rc.policy_template.create()
+
+    def test_delete_raises(self, mgmt_root):
+        rc = mgmt_root.tm.asm.policy_templates_s
+        with pytest.raises(UnsupportedOperation):
+            rc.policy_template.delete()
+
+    def test_modify_raises(self, mgmt_root):
+        rc = mgmt_root.tm.asm.policy_templates_s
+        with pytest.raises(UnsupportedOperation):
+            rc.policy_template.modify()
+
+    def test_refresh(self, mgmt_root):
+        res1, hashid = return_template(mgmt_root)
+        rc = mgmt_root.tm.asm.policy_templates_s
+        res2 = rc.policy_template.load(id=hashid)
+        assert res1.selfLink == res2.selfLink
+        assert res1.title == res2.title
+        assert res1.id == res2.id
+        assert res1.userDefined == res2.userDefined
+        res1.refresh()
+        assert res1.selfLink == res2.selfLink
+        assert res1.title == res2.title
+        assert res1.id == res2.id
+        assert res1.userDefined == res2.userDefined
+
+    def test_load_no_object(self, mgmt_root):
+        rc = mgmt_root.tm.asm.policy_templates_s
+        with pytest.raises(HTTPError) as err:
+            rc.policy_template.load(id='Lx3553-321')
+        assert err.value.response.status_code == 404
+
+    def test_load(self, mgmt_root):
+        _, hashid = return_template(mgmt_root)
+        rc = mgmt_root.tm.asm.policy_templates_s
+        res = rc.policy_template.load(id=hashid)
+        link = 'https://localhost/mgmt/tm/asm/policy-templates/'
+        assert res.selfLink.startswith(link + hashid)
+        assert res.id == hashid
+        assert res.userDefined is False
+
+    def test_collection(self, mgmt_root):
+        sc = mgmt_root.tm.asm.policy_templates_s.get_collection()
+        assert isinstance(sc, list)
+        assert len(sc)
+        assert isinstance(sc[0], Policy_Template)
diff --git a/f5/bigip/tm/asm/test/unit/test_policy_template.py b/f5/bigip/tm/asm/test/unit/test_policy_template.py
new file mode 100644
index 0000000..ace7fb4
--- /dev/null
+++ b/f5/bigip/tm/asm/test/unit/test_policy_template.py
@@ -0,0 +1,54 @@
+# Copyright 2017 F5 Networks Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import mock
+import pytest
+
+from f5.bigip import ManagementRoot
+from f5.bigip.tm.asm.policy_templates import Policy_Template
+from f5.sdk_exception import UnsupportedOperation
+from six import iterkeys
+
+
+@pytest.fixture
+def FakePolicyTemplate():
+    fake_asm = mock.MagicMock()
+    fake_tmpl = Policy_Template(fake_asm)
+    fake_tmpl._meta_data['bigip'].tmos_version = '11.6.0'
+    return fake_tmpl
+
+
+class TestPolicyTemplates(object):
+    def test_create_raises(self, FakePolicyTemplate):
+        with pytest.raises(UnsupportedOperation):
+            FakePolicyTemplate.create()
+
+    def test_modify_raises(self, FakePolicyTemplate):
+        with pytest.raises(UnsupportedOperation):
+            FakePolicyTemplate.modify()
+
+    def test_delete_raises(self, FakePolicyTemplate):
+        with pytest.raises(UnsupportedOperation):
+            FakePolicyTemplate.delete()
+
+    def test_collection(self, fakeicontrolsession):
+        b = ManagementRoot('192.168.1.1', 'admin', 'admin')
+        t = b.tm.asm.policy_templates_s
+        test_meta = t._meta_data['attribute_registry']
+        test_meta2 = t._meta_data['allowed_lazy_attributes']
+        kind = 'tm:asm:policy-templates:policy-templatestate'
+        assert kind in list(iterkeys(test_meta))
+        assert Policy_Template in test_meta2
+        assert t._meta_data['object_has_stats'] is False