Add policy json tests

Change-Id: I12210f8a704a52386137a7d8293f4fe200122cbd
Reviewed-on: https://review.gerrithub.io/377174
Reviewed-by: Dennis Dmitriev <dis.xcom@gmail.com>
Tested-by: Tatyanka Leontovich <tleontovich@mirantis.com>
diff --git a/tcp_tests/managers/execute_commands.py b/tcp_tests/managers/execute_commands.py
index 1965750..3c01867 100644
--- a/tcp_tests/managers/execute_commands.py
+++ b/tcp_tests/managers/execute_commands.py
@@ -203,7 +203,8 @@
             with self.__underlay.remote(node_name=node_name) as remote:
                 LOG.info("Uploading directory {0} to {1}:{2}"
                          .format(local_path, node_name, remote_path))
-                remote.upload(source=local_path.rstrip(), target=remote_path.rstrip())
+                remote.upload(source=local_path.rstrip(),
+                              target=remote_path.rstrip())
                 return
 
         result = {}
diff --git a/tcp_tests/settings_oslo.py b/tcp_tests/settings_oslo.py
index 86ef7b8..cb56399 100644
--- a/tcp_tests/settings_oslo.py
+++ b/tcp_tests/settings_oslo.py
@@ -32,6 +32,8 @@
     __name__, 'templates/{0}/salt.yaml'.format(settings.LAB_CONFIG_NAME))
 _default_environment_template_dir = pkg_resources.resource_filename(
     __name__, 'environment/')
+_default_templates_dir = pkg_resources.resource_filename(
+    __name__, 'templates/')
 _default_common_services_steps = pkg_resources.resource_filename(
     __name__,
     'templates/{0}/common-services.yaml'.format(
@@ -123,6 +125,9 @@
     ct.Cfg('environment_template_dir', ct.String(),
            help="Path to directory with Environment template and inventory",
            default=_default_environment_template_dir),
+    ct.Cfg('templates_dir', ct.String(),
+           help="Path to directory with templates",
+           default=_default_templates_dir),
 ]
 salt_opts = [
     ct.Cfg('salt_master_host', ct.IPAddress(),
@@ -370,8 +375,9 @@
     config.register_group(cfg.OptGroup(name='opencontrail',
                           title="Options for Juniper contrail-tests", help=""))
     config.register_opts(group='opencontrail', opts=opencontrail_opts)
-    config.register_group(cfg.OptGroup(name='stack_light',
-                                       title="StackLight config and credentials", help=""))
+    config.register_group(
+        cfg.OptGroup(name='stack_light',
+                     title="StackLight config and credentials", help=""))
     config.register_opts(group='stack_light', opts=sl_opts)
     config.register_group(
         cfg.OptGroup(name='sl_deploy',
diff --git a/tcp_tests/templates/virtual-mcp-ocata-dvr/openstack.yaml b/tcp_tests/templates/virtual-mcp-ocata-dvr/openstack.yaml
index db03390..68c05db 100644
--- a/tcp_tests/templates/virtual-mcp-ocata-dvr/openstack.yaml
+++ b/tcp_tests/templates/virtual-mcp-ocata-dvr/openstack.yaml
@@ -6,9 +6,28 @@
 {% from 'shared-salt.yaml' import IPV4_NET_EXTERNAL_PREFIX with context %}
 {% from 'shared-salt.yaml' import IPV4_NET_TENANT_PREFIX with context %}
 {% set PATTERN = os_env('PATTERN', 'smoke') %}
+{% set LAB_CONFIG_NAME = os_env('LAB_CONFIG_NAME') %}
 
 # Install OpenStack control services
 
+- description: Upload policy override
+  upload:
+    local_path:  {{ config.salt_deploy.templates_dir }}{{ LAB_CONFIG_NAME }}/
+    local_filename: overrides-policy.yml
+    remote_path: /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/
+  node_name: {{ HOSTNAME_CFG01 }}
+
+- description: Create custom cluster control class
+  cmd: echo -e "classes:\n- cluster.{{ LAB_CONFIG_NAME }}.openstack.control_orig\n$(cat /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/overrides-policy.yml)" > /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/overrides-policy.yml
+  node_name: {{ HOSTNAME_CFG01 }}
+
+- description: Rename control classes
+  cmd: mv /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/control.yml /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/control_orig.yml &&
+    ln -s /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/overrides-policy.yml /srv/salt/reclass/classes/cluster/{{ LAB_CONFIG_NAME }}/openstack/control.yml &&
+    salt --hard-crash --state-output=mixed --state-verbose=False '*' saltutil.sync_all &&
+    salt --hard-crash --state-output=mixed --state-verbose=False '*' saltutil.refresh_pillar
+  node_name: {{ HOSTNAME_CFG01 }}
+
 - description: Install glance on all controllers
   cmd: salt --hard-crash --state-output=mixed --state-verbose=False
      -C 'I@glance:server' state.sls glance -b 1
diff --git a/tcp_tests/templates/virtual-mcp-ocata-dvr/overrides-policy.yml b/tcp_tests/templates/virtual-mcp-ocata-dvr/overrides-policy.yml
new file mode 100644
index 0000000..1f35a6b
--- /dev/null
+++ b/tcp_tests/templates/virtual-mcp-ocata-dvr/overrides-policy.yml
@@ -0,0 +1,40 @@
+parameters:
+  nova:
+    controller:
+      policy:
+        context_is_admin: 'role:admin or role:administrator'
+        'compute:create': 'rule:admin_or_owner'
+        'compute:create:attach_network':
+  cinder:
+    controller:
+      policy:
+        'volume:delete': 'rule:admin_or_owner'
+        'volume:extend':
+  neutron:
+    server:
+      policy:
+        create_subnet: 'rule:admin_or_network_owner'
+        'get_network:queue_id': 'rule:admin_only'
+        'create_network:shared':
+  glance:
+    server:
+      policy:
+        publicize_image: "role:admin"
+        add_member:
+  keystone:
+    server:
+      policy:
+        admin_or_token_subject: 'rule:admin_required or rule:token_subject'
+  heat:
+    server:
+      policy:
+        context_is_admin: 'role:admin and is_admin_project:True'
+        deny_stack_user: 'not role:heat_stack_user'
+        deny_everybody: '!'
+        'cloudformation:ValidateTemplate': 'rule:deny_everybody'
+        'cloudformation:DescribeStackResources':
+  ceilometer:
+    server:
+      policy:
+        segregation: 'rule:context_is_admin'
+        'telemetry:get_resource':
diff --git a/tcp_tests/tests/system/test_openstack_service_policy.py b/tcp_tests/tests/system/test_openstack_service_policy.py
new file mode 100644
index 0000000..bf1ebb1
--- /dev/null
+++ b/tcp_tests/tests/system/test_openstack_service_policy.py
@@ -0,0 +1,415 @@
+#    Copyright 2017 Mirantis, 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 tcp_tests import logger
+
+LOG = logger.logger
+
+
+class OSServiceCheckers(object):
+    """docstring for OSServiceCheckers"""
+
+    def assert_res(self, r):
+        ret = r[0]
+        assert ret.get('return')
+        assert len(ret.get('return')[0]) == 3
+        hosts = ret.get('return')[0]
+        assert all(['PASS' in one[1] for one in hosts.items()])
+
+    def cmd_has(self, pattern, f):
+        cmd_has = '''(grep -q '{pattern}' {f}) && echo PASS || echo FAIL'''
+        cmd = cmd_has.format(pattern=pattern, f=f)
+        LOG.debug(cmd)
+        return cmd
+
+    def cmd_hasnt(self, pattern, f):
+        cmd_hasnt = \
+            '''(! grep -q '{pattern}' {f}) && echo PASS || echo FAIL'''
+        cmd = cmd_hasnt.format(pattern=pattern, f=f)
+        LOG.debug(cmd)
+        return cmd
+
+    def check_nova(self, salt):
+        cmd = self.cmd_has(
+            pattern='"context_is_admin":', f='/etc/nova/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@nova:controller', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_has(
+            pattern='"compute:create":', f='/etc/nova/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@nova:controller', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"compute:create:attach_network":',
+            f='/etc/nova/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@nova:controller', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_cinder(self, salt):
+        cmd = self.cmd_has(
+            pattern='"volume:delete":', f='/etc/cinder/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@cinder:controller', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"volume:extend":', f="/etc/cinder/policy.json")
+        LOG.info(cmd)
+        ret = salt.run_state('I@cinder:controller', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_heat(self, salt):
+        cmd = self.cmd_has(
+            pattern='"context_is_admin":', f='/etc/heat/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@heat:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_has(
+            pattern='"deny_stack_user":', f='/etc/heat/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@heat:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_has(
+            pattern='"deny_everybody":', f='/etc/heat/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@heat:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_has(
+            pattern='"cloudformation:ValidateTemplate":',
+            f='/etc/heat/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@heat:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"cloudformation:DescribeStackResources":',
+            f='/etc/heat/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@heat:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_glance(self, salt):
+        cmd = self.cmd_has(
+            pattern='"publicize_image":', f='/etc/glance/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@glance:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"add_member":', f='/etc/glance/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@glance:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_neutron(self, salt):
+        cmd = self.cmd_has(
+            pattern='"create_subnet":', f='/etc/neutron/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@neutron:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_has(
+            pattern='"get_network:queue_id":', f='/etc/neutron/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@neutron:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"create_network:shared":', f='/etc/neutron/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@neutron:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_ceilometer(self, salt):
+        cmd = self.cmd_has(
+            pattern='"segregation"', f='/etc/ceilometer/policy.json')
+        LOG.info(cmd)
+        ret = salt.run_state('I@ceilometer:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+        cmd = self.cmd_hasnt(
+            pattern='"telemetry:get_resource"',
+            f='/etc/ceilometer/policy.json')
+        ret = salt.run_state('I@ceilometer:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+    def check_keystone(self, salt):
+        cmd = self.cmd_has(
+            pattern='"admin_or_token_subject":', f='/etc/keystone/policy.json')
+
+        LOG.info(cmd)
+        ret = salt.run_state('I@keystone:server', 'cmd.run', cmd)
+        LOG.info(ret)
+        self.assert_res(ret)
+
+
+class TestOSAIOServicesPolicy(OSServiceCheckers):
+    """Test class for testing OpenStack services policy"""
+
+    def test_services_with_custom_policy_json(
+            self, underlay, openstack_deployed, salt_actions, show_step):
+        """Test add policy for Nova service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Verify nova policy.json
+            5. Verify cinder policy.json
+            6. Verify heat policy.json
+            7. Verify glance policy.json
+            8. Verify neutron policy.json
+            9. Verify keystone policy.json
+            10. Verify ceilometer policy.json. Skipped due absence of ceilometer  # noqa
+
+        """
+        salt = salt_actions
+        # STEP #1,2,3
+        show_step(1)
+        show_step(2)
+        show_step(3)
+
+        # STEP #4
+        show_step(4)
+        self.check_nova(salt)
+
+        # STEP #5
+        show_step(5)
+        self.check_cinder(salt)
+
+        # STEP #6
+        show_step(6)
+        self.check_heat(salt)
+
+        # STEP #7
+        show_step(7)
+        self.check_glance(salt)
+
+        # STEP #8
+        show_step(8)
+        self.check_neutron(salt)
+
+        # STEP #9
+        show_step(9)
+        self.check_keystone(salt)
+
+        # STEP #10
+        # FIXME: Enable when template has a ceilometer
+        # show_step(10)
+        # self.check_ceilometer(salt)
+
+        #
+        LOG.info("*************** DONE **************")
+
+
+class TestOSServicesPolicy(OSServiceCheckers):
+    """Test class for testing OpenStack services policy"""
+
+    # https://github.com/salt-formulas/salt-formula-nova/pull/17 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_nova(self, underlay, openstack_deployed, salt_actions,
+                             show_step):
+        """Test add policy for Nova service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        self.check_nova(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-cinder/pull/13 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_cinder(self, underlay, openstack_deployed,
+                               salt_actions, show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_cinder(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-heat/pull/5 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_heat(self, underlay, openstack_deployed, salt_actions,
+                             show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_heat(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-glance/pull/9 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_glance(self, underlay, openstack_deployed,
+                               salt_actions, show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_cinder(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-ceilometer/pull/2 - Merged
+    @pytest.mark.fail_snapshot
+    @pytest.mark.skip(reason="Skipped due no have ceilometer in environment")
+    def test_policy_for_ceilometer(self, underlay, openstack_deployed,
+                                   salt_actions, show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_ceilometer(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-neutron/pull/8 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_neutron(self, underlay, openstack_deployed,
+                                salt_actions, show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_neutron(salt)
+        LOG.info("*************** DONE **************")
+
+    # https://github.com/salt-formulas/salt-formula-keystone/pull/11 - Merged
+    @pytest.mark.fail_snapshot
+    def test_policy_for_keystone(self, underlay, openstack_deployed,
+                                 salt_actions, show_step):
+        """Test add policy for Cinder service
+
+        Scenario:
+            1. Prepare salt on hosts
+            2. Setup controller nodes
+            3. Setup compute nodes
+            4. Add policy for service
+            5. Regenerate by salt
+            6. Verify
+
+        """
+        salt = salt_actions
+        show_step(1)
+        show_step(2)
+        show_step(3)
+        show_step(4)
+        show_step(5)
+        show_step(6)
+        self.check_keystone(salt)
+        LOG.info("*************** DONE **************")