Merge "trivial: Drop empty services folder under patrole_tempest_plugin"
diff --git a/.zuul.yaml b/.zuul.yaml
index 60f0d05..21b5679 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -29,8 +29,20 @@
- job:
name: patrole-base-multinode
- parent: legacy-dsvm-base-multinode
+ parent: tempest-multinode-full
+ description: |-
+ Patrole base job for multinode and "slow" tests where "slow" tests include:
+
+ * Tests that take more than ~30 seconds to run.
+ * Tests that experience spurious failures related to servers, volumes,
+ backups and similar resources failing to build.
timeout: 7800
+ branches:
+ - master
+ required-projects:
+ - openstack-infra/devstack-gate
+ - openstack/tempest
+ - openstack/patrole
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
@@ -38,10 +50,17 @@
- ^patrole/patrole_tempest_plugin/tests/unit/.*$
- ^releasenotes/.*
- ^setup.cfg$
- required-projects:
- - openstack-infra/devstack-gate
- - openstack/patrole
- - openstack/tempest
+ vars:
+ devstack_localrc:
+ TEMPEST_PLUGINS: "'{{ ansible_user_dir }}/src/git.openstack.org/openstack/patrole'"
+ devstack_plugins:
+ patrole: git://git.openstack.org/openstack/patrole.git
+ devstack_services:
+ tempest: true
+ neutron: true
+ tempest_concurrency: 1
+ tempest_test_regex: (?=.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api)
+ tox_envlist: all-plugin
- job:
name: patrole-admin
@@ -77,18 +96,18 @@
- job:
name: patrole-multinode-admin
parent: patrole-base-multinode
- run: playbooks/patrole-multinode-admin/run.yaml
- post-run: playbooks/patrole-multinode-admin/post.yaml
voting: false
- nodeset: legacy-ubuntu-xenial-2-node
+ vars:
+ devstack_localrc:
+ RBAC_TEST_ROLE: admin
- job:
name: patrole-multinode-member
parent: patrole-base-multinode
- run: playbooks/patrole-multinode-member/run.yaml
- post-run: playbooks/patrole-multinode-member/post.yaml
voting: false
- nodeset: legacy-ubuntu-xenial-2-node
+ vars:
+ devstack_localrc:
+ RBAC_TEST_ROLE: member
- job:
name: patrole-py35-member
diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index 7d48870..23a210a 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -82,10 +82,10 @@
Patrole currently only supports custom JSON policy files.
- :param int expected_error_code: Overrides default value of 403 (Forbidden)
- with endpoint-specific error code. Currently only supports 403 and 404.
- Support for 404 is needed because some services, like Neutron,
- intentionally throw a 404 for security reasons.
+ :param int expected_error_code: (DEPRECATED) Overrides default value of 403
+ (Forbidden) with endpoint-specific error code. Currently only supports
+ 403 and 404. Support for 404 is needed because some services, like
+ Neutron, intentionally throw a 404 for security reasons.
.. warning::
@@ -99,6 +99,7 @@
in the rules list.
Example::
+
rules=["api_action1", "api_action2"]
expected_error_codes=[404, 403]
diff --git a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
index 6b03ebe..2756a10 100644
--- a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
@@ -50,8 +50,8 @@
@decorators.idempotent_id('8ca68fdb-eaf6-4880-af82-ba0982949dec')
@rbac_rule_validation.action(service="neutron",
- rule="update_agent",
- expected_error_code=404)
+ rules=["get_agent", "update_agent"],
+ expected_error_codes=[404, 403])
def test_update_agent(self):
"""Update agent test.
diff --git a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
index 20e4aa7..ed52c34 100644
--- a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
@@ -73,8 +73,11 @@
with self.rbac_utils.override_role(self):
self._create_floatingip()
- @rbac_rule_validation.action(service="neutron",
- rule="create_floatingip:floating_ip_address")
+ @rbac_rule_validation.action(
+ service="neutron",
+ rules=["create_floatingip",
+ "create_floatingip:floating_ip_address"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('a8bb826a-403d-4130-a55d-120a0a660806')
def test_create_floating_ip_floatingip_address(self):
"""Create floating IP with address.
@@ -87,7 +90,8 @@
self._create_floatingip(floating_ip_address=fip)
@rbac_rule_validation.action(service="neutron",
- rule="update_floatingip")
+ rules=["get_floatingip", "update_floatingip"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('2ab1b060-19f8-4ef6-a838-e2ab7b377c63')
def test_update_floating_ip(self):
"""Update floating IP.
@@ -115,8 +119,8 @@
self.floating_ips_client.show_floatingip(floating_ip['id'])
@rbac_rule_validation.action(service="neutron",
- rule="delete_floatingip",
- expected_error_code=404)
+ rules=["get_floatingip", "delete_floatingip"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('2611b068-30d4-4241-a78f-1b801a14db7e')
def test_delete_floating_ip(self):
"""Delete floating IP.
diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
index 7a9d814..adab1e6 100644
--- a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
@@ -88,8 +88,9 @@
label_rule['id'])
@rbac_rule_validation.action(service="neutron",
- rule="delete_metering_label_rule",
- expected_error_code=404)
+ rules=["get_metering_label_rule",
+ "delete_metering_label_rule"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('e3adc88c-05c0-43a7-8e32-63947ae4890e')
def test_delete_metering_label_rule(self):
"""Delete metering label rule.
diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
index abd7326..0231868 100644
--- a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
@@ -71,8 +71,9 @@
self.metering_labels_client.show_metering_label(label['id'])
@rbac_rule_validation.action(service="neutron",
- rule="delete_metering_label",
- expected_error_code=404)
+ rules=["get_metering_label",
+ "delete_metering_label"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('1621ccfe-2e3f-4d16-98aa-b620f9d00404')
def test_delete_metering_label(self):
"""Delete metering label.
diff --git a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
index 1dee46b..0097c7b 100644
--- a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
@@ -66,7 +66,9 @@
return network
@rbac_rule_validation.action(service="neutron",
- rule="create_network:segments")
+ rules=["create_network",
+ "create_network:segments"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('9e1d0c3d-92e3-40e3-855e-bfbb72ea6e0b')
def test_create_network_segments(self):
"""Create network with segments.
@@ -77,7 +79,9 @@
self._create_network_segments()
@rbac_rule_validation.action(service="neutron",
- rule="update_network:segments")
+ rules=["get_network", "update_network",
+ "update_network:segments"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('0f45232a-7b59-4bb1-9a91-db77d0a8cc9b')
def test_update_network_segments(self):
"""Update network segments.
@@ -92,7 +96,9 @@
segments=new_segments)
@rbac_rule_validation.action(service="neutron",
- rule="get_network:segments")
+ rules=["get_network",
+ "get_network:segments"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('094ff9b7-0c3b-4515-b19b-b9d2031337bd')
def test_show_network_segments(self):
"""Show network segments.
@@ -113,4 +119,4 @@
LOG.info("NotFound or Forbidden exception are not thrown when "
"role doesn't have access to the endpoint. Instead, "
"the response will have an empty network body.")
- raise rbac_exceptions.RbacMalformedResponse(True)
+ raise rbac_exceptions.RbacMalformedResponse(empty=True)
diff --git a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
index 932683d..1a0e186 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
@@ -99,7 +99,9 @@
self._create_network()
@rbac_rule_validation.action(service="neutron",
- rule="create_network:shared")
+ rules=["create_network",
+ "create_network:shared"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('ccabf2a9-28c8-44b2-80e6-ffd65d43eef2')
def test_create_network_shared(self):
@@ -112,7 +114,9 @@
@utils.requires_ext(extension='external-net', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="create_network:router:external")
+ rules=["create_network",
+ "create_network:router:external"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('51adf2a7-739c-41e0-8857-3b4c460cbd24')
def test_create_network_router_external(self):
@@ -124,8 +128,11 @@
self._create_network(router_external=True)
@utils.requires_ext(extension='provider', service='network')
- @rbac_rule_validation.action(service="neutron",
- rule="create_network:provider:network_type")
+ @rbac_rule_validation.action(
+ service="neutron",
+ rules=["create_network",
+ "create_network:provider:network_type"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('3c42f7b8-b80c-44ef-8fa4-69ec4b1836bc')
def test_create_network_provider_network_type(self):
@@ -139,7 +146,9 @@
@utils.requires_ext(extension='provider', service='network')
@rbac_rule_validation.action(
service="neutron",
- rule="create_network:provider:segmentation_id")
+ rules=["create_network",
+ "create_network:provider:segmentation_id"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('b9decb7b-68ef-4504-b99b-41edbf7d2af5')
def test_create_network_provider_segmentation_id(self):
@@ -152,7 +161,8 @@
provider_segmentation_id=200)
@rbac_rule_validation.action(service="neutron",
- rule="update_network")
+ rules=["get_network", "update_network"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('6485bb4e-e110-48ae-83e1-3ec8b40c3107')
def test_update_network(self):
@@ -167,7 +177,10 @@
self._update_network(name=updated_name)
@rbac_rule_validation.action(service="neutron",
- rule="update_network:shared")
+ rules=["get_network",
+ "update_network",
+ "update_network:shared"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('37ea3e33-47d9-49fc-9bba-1af98fbd46d6')
def test_update_network_shared(self):
@@ -181,7 +194,10 @@
@utils.requires_ext(extension='external-net', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="update_network:router:external")
+ rules=["get_network",
+ "update_network",
+ "update_network:router:external"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('34884c22-499b-4960-97f1-e2ed8522a9c9')
def test_update_network_router_external(self):
@@ -194,7 +210,8 @@
self._update_network(net_id=network['id'], router_external=True)
@rbac_rule_validation.action(service="neutron",
- rule="get_network")
+ rule="get_network",
+ expected_error_code=404)
@decorators.idempotent_id('0eb62d04-338a-4ff4-a8fa-534e52110534')
def test_show_network(self):
@@ -207,7 +224,9 @@
@utils.requires_ext(extension='external-net', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_network:router:external")
+ rules=["get_network",
+ "get_network:router:external"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('529e4814-22e9-413f-af48-8fefcd637344')
def test_show_network_router_external(self):
@@ -218,12 +237,17 @@
kwargs = {'fields': 'router:external'}
with self.rbac_utils.override_role(self):
- self.networks_client.show_network(self.network['id'],
- **kwargs)
+ retrieved_network = self.networks_client.show_network(
+ self.network['id'], **kwargs)['network']
+
+ if len(retrieved_network) == 0:
+ raise rbac_exceptions.RbacMalformedResponse(empty=True)
@utils.requires_ext(extension='provider', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_network:provider:network_type")
+ rules=["get_network",
+ "get_network:provider:network_type"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('6521dd60-0950-458b-8491-09d3c84ac0f4')
def test_show_network_provider_network_type(self):
@@ -238,11 +262,14 @@
self.network['id'], **kwargs)['network']
if len(retrieved_network) == 0:
- raise rbac_exceptions.RbacMalformedResponse(True)
+ raise rbac_exceptions.RbacMalformedResponse(empty=True)
@utils.requires_ext(extension='provider', service='network')
- @rbac_rule_validation.action(service="neutron",
- rule="get_network:provider:physical_network")
+ @rbac_rule_validation.action(
+ service="neutron",
+ rules=["get_network",
+ "get_network:provider:physical_network"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('c049f11a-240c-4a85-ad43-a4d3fd0a5e39')
def test_show_network_provider_physical_network(self):
@@ -260,8 +287,11 @@
raise rbac_exceptions.RbacMalformedResponse(empty=True)
@utils.requires_ext(extension='provider', service='network')
- @rbac_rule_validation.action(service="neutron",
- rule="get_network:provider:segmentation_id")
+ @rbac_rule_validation.action(
+ service="neutron",
+ rules=["get_network",
+ "get_network:provider:segmentation_id"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('38d9f085-6365-4f81-bac9-c53c294d727e')
def test_show_network_provider_segmentation_id(self):
@@ -278,11 +308,9 @@
if len(retrieved_network) == 0:
raise rbac_exceptions.RbacMalformedResponse(empty=True)
- key = retrieved_network.get('provider:segmentation_id', "NotFound")
- self.assertNotEqual(key, "NotFound")
-
@rbac_rule_validation.action(service="neutron",
- rule="delete_network")
+ rules=["get_network", "delete_network"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('56ca50ed-ac58-49d6-b239-ed39e7124d5c')
def test_delete_network(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
index a8c7d68..2cf3cd6 100644
--- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
@@ -68,7 +68,9 @@
@decorators.idempotent_id('045ee797-4962-4913-b96a-5d7ea04099e7')
@rbac_rule_validation.action(service="neutron",
- rule="create_port:device_owner")
+ rules=["create_port",
+ "create_port:device_owner"],
+ expected_error_codes=[403, 403])
def test_create_port_device_owner(self):
with self.rbac_utils.override_role(self):
self.create_port(self.network,
@@ -76,14 +78,18 @@
@decorators.idempotent_id('c4fa8844-f5ef-4daa-bfa2-b89897dfaedf')
@rbac_rule_validation.action(service="neutron",
- rule="create_port:port_security_enabled")
+ rules=["create_port",
+ "create_port:port_security_enabled"],
+ expected_error_codes=[403, 403])
def test_create_port_security_enabled(self):
with self.rbac_utils.override_role(self):
self.create_port(self.network, port_security_enabled=True)
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="create_port:binding:host_id")
+ rules=["create_port",
+ "create_port:binding:host_id"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('a54bd6b8-a7eb-4101-bfe8-093930b0d660')
def test_create_port_binding_host_id(self):
@@ -95,7 +101,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="create_port:binding:profile")
+ rules=["create_port",
+ "create_port:binding:profile"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('98fa38ab-c2ed-46a0-99f0-59f18cbd257a')
def test_create_port_binding_profile(self):
@@ -111,7 +119,9 @@
CONF.policy_feature_enabled.create_port_fixed_ips_ip_address_policy,
'"create_port:fixed_ips:ip_address" must be available in the cloud.')
@rbac_rule_validation.action(service="neutron",
- rule="create_port:fixed_ips:ip_address")
+ rules=["create_port",
+ "create_port:fixed_ips:ip_address"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('2551e10d-006a-413c-925a-8c6f834c09ac')
def test_create_port_fixed_ips_ip_address(self):
@@ -126,7 +136,9 @@
self.create_port(**post_body)
@rbac_rule_validation.action(service="neutron",
- rule="create_port:mac_address")
+ rules=["create_port",
+ "create_port:mac_address"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('aee6d0be-a7f3-452f-aefc-796b4eb9c9a8')
def test_create_port_mac_address(self):
@@ -137,7 +149,9 @@
self.create_port(**post_body)
@rbac_rule_validation.action(service="neutron",
- rule="create_port:allowed_address_pairs")
+ rules=["create_port",
+ "create_port:allowed_address_pairs"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('b638d1f4-d903-4ca8-aa2a-6fd603c5ec3a')
def test_create_port_allowed_address_pairs(self):
@@ -161,7 +175,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_port:binding:vif_type")
+ rules=["get_port",
+ "get_port:binding:vif_type"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('125aff0b-8fed-4f8e-8410-338616594b06')
def test_show_port_binding_vif_type(self):
@@ -179,7 +195,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_port:binding:vif_details")
+ rules=["get_port",
+ "get_port:binding:vif_details"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('e42bfd77-fcce-45ee-9728-3424300f0d6f')
def test_show_port_binding_vif_details(self):
@@ -197,7 +215,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_port:binding:host_id")
+ rules=["get_port",
+ "get_port:binding:host_id"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('8e61bcdc-6f81-443c-833e-44410266551e')
def test_show_port_binding_host_id(self):
@@ -218,7 +238,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_port:binding:profile")
+ rules=["get_port",
+ "get_port:binding:profile"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('d497cea9-c4ad-42e0-acc9-8d257d6b01fc')
def test_show_port_binding_profile(self):
@@ -239,7 +261,8 @@
attribute='binding:profile')
@rbac_rule_validation.action(service="neutron",
- rule="update_port")
+ rules=["get_port", "update_port"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('afa80981-3c59-42fd-9531-3bcb2cd03711')
def test_update_port(self):
with self.rbac_utils.override_role(self):
@@ -250,7 +273,9 @@
@decorators.idempotent_id('08d70f59-67cb-4fb1-bd6c-a5e59dd5db2b')
@rbac_rule_validation.action(service="neutron",
- rule="update_port:device_owner")
+ rules=["get_port", "update_port",
+ "update_port:device_owner"],
+ expected_error_codes=[404, 403, 403])
def test_update_port_device_owner(self):
original_device_owner = self.port['device_owner']
@@ -261,7 +286,9 @@
device_owner=original_device_owner)
@rbac_rule_validation.action(service="neutron",
- rule="update_port:mac_address")
+ rules=["get_port", "update_port",
+ "update_port:mac_address"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('507140c8-7b14-4d63-b627-2103691d887e')
def test_update_port_mac_address(self):
original_mac_address = self.port['mac_address']
@@ -276,7 +303,9 @@
CONF.policy_feature_enabled.update_port_fixed_ips_ip_address_policy,
'"update_port:fixed_ips:ip_address" must be available in the cloud.')
@rbac_rule_validation.action(service="neutron",
- rule="update_port:fixed_ips:ip_address")
+ rules=["get_port", "update_port",
+ "update_port:fixed_ips:ip_address"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('c091c825-532b-4c6f-a14f-affd3259c1c3')
def test_update_port_fixed_ips_ip_address(self):
@@ -291,15 +320,20 @@
self.ports_client.update_port(port['id'], fixed_ips=fixed_ips)
@rbac_rule_validation.action(service="neutron",
- rule="update_port:port_security_enabled")
+ rules=["get_port", "update_port",
+ "update_port:port_security_enabled"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('795541af-6652-4e35-9581-fd58224f7545')
def test_update_port_security_enabled(self):
with self.rbac_utils.override_role(self):
- self.ports_client.update_port(self.port['id'], security_groups=[])
+ self.ports_client.update_port(self.port['id'],
+ port_security_enabled=True)
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="update_port:binding:host_id")
+ rules=["get_port", "update_port",
+ "update_port:binding:host_id"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('24206a72-0d90-4712-918c-5c9a1ebef64d')
def test_update_port_binding_host_id(self):
@@ -315,7 +349,9 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="update_port:binding:profile")
+ rules=["get_port", "update_port",
+ "update_port:binding:profile"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('990ea8d1-9257-4f71-a3bf-d6d0914625c5')
def test_update_port_binding_profile(self):
@@ -333,7 +369,9 @@
self.ports_client.update_port(**updated_body)
@rbac_rule_validation.action(service="neutron",
- rule="update_port:allowed_address_pairs")
+ rules=["get_port", "update_port",
+ "update_port:allowed_address_pairs"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('729c2151-bb49-4f4f-9d58-3ed8819b7582')
def test_update_port_allowed_address_pairs(self):
@@ -349,8 +387,8 @@
allowed_address_pairs=address_pairs)
@rbac_rule_validation.action(service="neutron",
- rule="delete_port",
- expected_error_code=404)
+ rules=["get_port", "delete_port"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('1cf8e582-bc09-46cb-b32a-82bf991ad56f')
def test_delete_port(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
index 812b0c1..a3d973d 100644
--- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
@@ -71,7 +71,9 @@
@decorators.idempotent_id('6139eb97-95c0-40d8-a109-99de11ab2e5e')
@utils.requires_ext(extension='l3-ha', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="create_router:ha")
+ rules=["create_router",
+ "create_router:ha"],
+ expected_error_codes=[403, 403])
def test_create_high_availability_router(self):
"""Create high-availability router
@@ -85,7 +87,9 @@
@decorators.idempotent_id('c6254ca6-2728-412d-803d-d4aa3935e56d')
@utils.requires_ext(extension='dvr', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="create_router:distributed")
+ rules=["create_router",
+ "create_router:distributed"],
+ expected_error_codes=[403, 403])
def test_create_distributed_router(self):
"""Create distributed router
@@ -99,7 +103,9 @@
@utils.requires_ext(extension='ext-gw-mode', service='network')
@rbac_rule_validation.action(
service="neutron",
- rule="create_router:external_gateway_info:enable_snat")
+ rules=["create_router",
+ "create_router:external_gateway_info:enable_snat"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('3c5acd49-0ec7-4109-ab51-640557b48ebc')
def test_create_router_enable_snat(self):
"""Create Router Snat
@@ -119,7 +125,9 @@
@rbac_rule_validation.action(
service="neutron",
- rule="create_router:external_gateway_info:external_fixed_ips")
+ rules=["create_router",
+ "create_router:external_gateway_info:external_fixed_ips"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('d0354369-a040-4349-b869-645c8aed13cd')
def test_create_router_external_fixed_ips(self):
"""Create Router Fixed IPs
@@ -158,7 +166,9 @@
@decorators.idempotent_id('3ed26ea2-b419-410c-b4b5-576c1edafa06')
@utils.requires_ext(extension='dvr', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_router:distributed")
+ rules=["get_router",
+ "get_router:distributed"],
+ expected_error_codes=[404, 403])
def test_show_distributed_router(self):
"""Get distributed router
@@ -179,7 +189,8 @@
@decorators.idempotent_id('defc502c-4159-4824-b4d9-3cdcc39015b2')
@utils.requires_ext(extension='l3-ha', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="get_router:ha")
+ rules=["get_router", "get_router:ha"],
+ expected_error_codes=[404, 403])
def test_show_high_availability_router(self):
"""GET high-availability router
@@ -197,8 +208,9 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute='ha')
- @rbac_rule_validation.action(
- service="neutron", rule="update_router")
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_router", "update_router"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('3d182f4e-0023-4218-9aa0-ea2b0ae0bd7a')
def test_update_router(self):
"""Update Router
@@ -210,8 +222,10 @@
with self.rbac_utils.override_role(self):
self.routers_client.update_router(self.router['id'], name=new_name)
- @rbac_rule_validation.action(
- service="neutron", rule="update_router:external_gateway_info")
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_router", "update_router",
+ "update_router:external_gateway_info"],
+ expected_error_codes=[404, 403, 403])
@decorators.idempotent_id('5a6ae104-a9c3-4b56-8622-e1a0a0194474')
def test_update_router_external_gateway_info(self):
"""Update Router External Gateway Info
@@ -225,7 +239,10 @@
@rbac_rule_validation.action(
service="neutron",
- rule="update_router:external_gateway_info:network_id")
+ rules=["get_router", "update_router",
+ "update_router:external_gateway_info",
+ "update_router:external_gateway_info:network_id"],
+ expected_error_codes=[404, 403, 403, 403])
@decorators.idempotent_id('f1fc5a23-e3d8-44f0-b7bc-47006ad9d3d4')
def test_update_router_external_gateway_info_network_id(self):
"""Update Router External Gateway Info Network Id
@@ -245,7 +262,10 @@
@utils.requires_ext(extension='ext-gw-mode', service='network')
@rbac_rule_validation.action(
service="neutron",
- rule="update_router:external_gateway_info:enable_snat")
+ rules=["get_router", "update_router",
+ "update_router:external_gateway_info",
+ "update_router:external_gateway_info:enable_snat"],
+ expected_error_codes=[404, 403, 403, 403])
@decorators.idempotent_id('515a2954-3d79-4695-aeb9-d1c222765840')
def test_update_router_enable_snat(self):
"""Update Router External Gateway Info Enable Snat
@@ -265,7 +285,10 @@
@rbac_rule_validation.action(
service="neutron",
- rule="update_router:external_gateway_info:external_fixed_ips")
+ rules=["get_router", "update_router",
+ "update_router:external_gateway_info",
+ "update_router:external_gateway_info:external_fixed_ips"],
+ expected_error_codes=[404, 403, 403, 403])
@decorators.idempotent_id('f429e5ee-8f0a-4667-963e-72dd95d5adee')
def test_update_router_external_fixed_ips(self):
"""Update Router External Gateway Info External Fixed Ips
@@ -291,7 +314,9 @@
@decorators.idempotent_id('ddc20731-dea1-4321-9abf-8772bf0b5977')
@utils.requires_ext(extension='l3-ha', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="update_router:ha")
+ rules=["get_router", "update_router",
+ "update_router:ha"],
+ expected_error_codes=[404, 403, 403])
def test_update_high_availability_router(self):
"""Update high-availability router
@@ -305,7 +330,9 @@
@decorators.idempotent_id('e1932c19-8f73-41cd-b5d2-84c7ae5d530c')
@utils.requires_ext(extension='dvr', service='network')
@rbac_rule_validation.action(service="neutron",
- rule="update_router:distributed")
+ rules=["get_router", "update_router",
+ "update_router:distributed"],
+ expected_error_codes=[404, 403, 403])
def test_update_distributed_router(self):
"""Update distributed router
@@ -318,7 +345,8 @@
distributed=False)
@rbac_rule_validation.action(service="neutron",
- rule="delete_router")
+ rules=["get_router", "delete_router"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('c0634dd5-0467-48f7-a4ae-1014d8edb2a7')
def test_delete_router(self):
"""Delete Router
@@ -352,7 +380,9 @@
subnet_id=subnet['id'])
@rbac_rule_validation.action(service="neutron",
- rule="remove_router_interface")
+ rules=["get_router",
+ "remove_router_interface"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('ff2593a4-2bff-4c27-97d3-dd3702b27dfb')
def test_remove_router_interface(self):
"""Remove Router Interface
diff --git a/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py b/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
index 8889e75..1cf841d 100644
--- a/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
@@ -81,15 +81,16 @@
rule="get_security_group",
expected_error_code=404)
@decorators.idempotent_id('56335e77-aef2-4b54-86c7-7f772034b585')
- def test_show_security_groups(self):
+ def test_show_security_group(self):
with self.rbac_utils.override_role(self):
self.security_groups_client.show_security_group(
self.secgroup['id'])
@rbac_rule_validation.action(service="neutron",
- rule="delete_security_group",
- expected_error_code=404)
+ rules=["get_security_group",
+ "delete_security_group"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('0b1330fd-dd28-40f3-ad73-966052e4b3de')
def test_delete_security_group(self):
@@ -100,8 +101,9 @@
self.security_groups_client.delete_security_group(secgroup_id)
@rbac_rule_validation.action(service="neutron",
- rule="update_security_group",
- expected_error_code=404)
+ rules=["get_security_group",
+ "update_security_group"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('56c5e4dc-f8aa-11e6-bc64-92361f002671')
def test_update_security_group(self):
@@ -135,8 +137,9 @@
self._create_security_group_rule()
@rbac_rule_validation.action(service="neutron",
- rule="delete_security_group_rule",
- expected_error_code=404)
+ rules=["get_security_group_rule",
+ "delete_security_group_rule"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('2262539e-b7d9-438c-acf9-a5ce0613be28')
def test_delete_security_group_rule(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
index fe14c92..124b59a 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
@@ -64,7 +64,9 @@
self._create_subnetpool()
@rbac_rule_validation.action(service="neutron",
- rule="create_subnetpool:shared")
+ rules=["create_subnetpool",
+ "create_subnetpool:shared"],
+ expected_error_codes=[403, 403])
@decorators.idempotent_id('cf730989-0d47-40bc-b39a-99e7de484723')
def test_create_subnetpool_shared(self):
"""Create subnetpool shared.
@@ -88,7 +90,9 @@
self.subnetpools_client.show_subnetpool(subnetpool['id'])
@rbac_rule_validation.action(service="neutron",
- rule="update_subnetpool")
+ rules=["get_subnetpool",
+ "update_subnetpool"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('1e79cead-5081-4be2-a4f7-484c0f443b9b')
def test_update_subnetpool(self):
"""Update subnetpool.
@@ -102,7 +106,9 @@
@decorators.idempotent_id('a16f4e5c-0675-415f-b636-00af00638693')
@rbac_rule_validation.action(service="neutron",
- rule="update_subnetpool:is_default")
+ rules=["update_subnetpool",
+ "update_subnetpool:is_default"],
+ expected_error_codes=[403, 403])
def test_update_subnetpool_is_default(self):
"""Update default subnetpool.
@@ -122,7 +128,9 @@
default_pool['id'], description=original_desc, is_default=True)
@rbac_rule_validation.action(service="neutron",
- rule="delete_subnetpool")
+ rules=["get_subnetpool",
+ "delete_subnetpool"],
+ expected_error_codes=[404, 403])
@decorators.idempotent_id('50f5944e-43e5-457b-ab50-fb48a73f0d3e')
def test_delete_subnetpool(self):
"""Delete subnetpool.
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
index 12d20fa..77d4b42 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
@@ -50,7 +50,8 @@
@decorators.idempotent_id('c02618e7-bb20-4abd-83c8-6eec2af08752')
@rbac_rule_validation.action(service="neutron",
- rule="get_subnet")
+ rule="get_subnet",
+ expected_error_code=404)
def test_show_subnet(self):
"""Show subnet.
@@ -76,7 +77,8 @@
@decorators.idempotent_id('f36cd821-dd22-4bd0-b43d-110fc4b553eb')
@rbac_rule_validation.action(service="neutron",
- rule="update_subnet")
+ rules=["get_subnet", "update_subnet"],
+ expected_error_codes=[404, 403])
def test_update_subnet(self):
"""Update subnet.
@@ -90,7 +92,8 @@
@decorators.idempotent_id('bcfc7153-bbd1-43a4-a908-b3e1b0cde0dc')
@rbac_rule_validation.action(service="neutron",
- rule="delete_subnet")
+ rules=["get_subnet", "delete_subnet"],
+ expected_error_codes=[404, 403])
def test_delete_subnet(self):
"""Delete subnet.
diff --git a/playbooks/patrole-multinode-admin/post.yaml b/playbooks/patrole-multinode-admin/post.yaml
deleted file mode 100644
index dac8753..0000000
--- a/playbooks/patrole-multinode-admin/post.yaml
+++ /dev/null
@@ -1,80 +0,0 @@
-- hosts: primary
- tasks:
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*nose_results.html
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*testr_results.html.gz
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/.testrepository/tmp*
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*testrepository.subunit.gz
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}/tox'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/.tox/*/log/*
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/logs/**
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
diff --git a/playbooks/patrole-multinode-admin/run.yaml b/playbooks/patrole-multinode-admin/run.yaml
deleted file mode 100644
index bece4e2..0000000
--- a/playbooks/patrole-multinode-admin/run.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-- hosts: primary
- name: Autoconverted job legacy-tempest-dsvm-patrole-multinode-admin from old job
- gate-tempest-dsvm-patrole-multinode-admin-ubuntu-xenial-nv
- tasks:
-
- - name: Ensure legacy workspace directory
- file:
- path: '{{ ansible_user_dir }}/workspace'
- state: directory
-
- - shell:
- cmd: |
- set -e
- set -x
- cat > clonemap.yaml << EOF
- clonemap:
- - name: openstack-infra/devstack-gate
- dest: devstack-gate
- EOF
- /usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
- git://git.openstack.org \
- openstack-infra/devstack-gate
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'
-
- - shell:
- cmd: |
- set -e
- set -x
- cat << 'EOF' >>"/tmp/dg-local.conf"
- [[local|localrc]]
- enable_plugin patrole git://git.openstack.org/openstack/patrole
- TEMPEST_PLUGINS='/opt/stack/new/patrole'
- # Needed by Patrole devstack plugin
- RBAC_TEST_ROLE=admin
- EOF
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'
-
- - shell:
- cmd: |
- set -e
- set -x
- export PYTHONUNBUFFERED=true
- # Ensure that tempest set up is executed, but do not automatically
- # execute tempest tests; they are executed in post_test_hook.
- export DEVSTACK_GATE_TEMPEST=1
- export DEVSTACK_GATE_NEUTRON=1
- export DEVSTACK_GATE_TOPOLOGY="multinode"
- export DEVSTACK_GATE_TEMPEST_REGEX='(?=.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api)'
- export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
- export PROJECTS="openstack/patrole $PROJECTS"
- export BRANCH_OVERRIDE=default
- if [ "$BRANCH_OVERRIDE" != "default" ] ; then
- export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
- fi
- cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
- ./safe-devstack-vm-gate-wrap.sh
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'
diff --git a/playbooks/patrole-multinode-member/post.yaml b/playbooks/patrole-multinode-member/post.yaml
deleted file mode 100644
index dac8753..0000000
--- a/playbooks/patrole-multinode-member/post.yaml
+++ /dev/null
@@ -1,80 +0,0 @@
-- hosts: primary
- tasks:
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*nose_results.html
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*testr_results.html.gz
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/.testrepository/tmp*
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=**/*testrepository.subunit.gz
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}/tox'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/.tox/*/log/*
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
-
- - name: Copy files from {{ ansible_user_dir }}/workspace/ on node
- synchronize:
- src: '{{ ansible_user_dir }}/workspace/'
- dest: '{{ zuul.executor.log_root }}'
- mode: pull
- copy_links: true
- verify_host: true
- rsync_opts:
- - --include=/logs/**
- - --include=*/
- - --exclude=*
- - --prune-empty-dirs
diff --git a/playbooks/patrole-multinode-member/run.yaml b/playbooks/patrole-multinode-member/run.yaml
deleted file mode 100644
index 4c7b70f..0000000
--- a/playbooks/patrole-multinode-member/run.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-- hosts: primary
- name: Autoconverted job legacy-tempest-dsvm-patrole-multinode-member from old job
- gate-tempest-dsvm-patrole-multinode-member-ubuntu-xenial-nv
- tasks:
-
- - name: Ensure legacy workspace directory
- file:
- path: '{{ ansible_user_dir }}/workspace'
- state: directory
-
- - shell:
- cmd: |
- set -e
- set -x
- cat > clonemap.yaml << EOF
- clonemap:
- - name: openstack-infra/devstack-gate
- dest: devstack-gate
- EOF
- /usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \
- git://git.openstack.org \
- openstack-infra/devstack-gate
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'
-
- - shell:
- cmd: |
- set -e
- set -x
- cat << 'EOF' >>"/tmp/dg-local.conf"
- [[local|localrc]]
- enable_plugin patrole git://git.openstack.org/openstack/patrole
- TEMPEST_PLUGINS='/opt/stack/new/patrole'
- # Needed by Patrole devstack plugin
- RBAC_TEST_ROLE=member
- EOF
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'
-
- - shell:
- cmd: |
- set -e
- set -x
- export PYTHONUNBUFFERED=true
- # Ensure that tempest set up is executed, but do not automatically
- # execute tempest tests; they are executed in post_test_hook.
- export DEVSTACK_GATE_TEMPEST=1
- export DEVSTACK_GATE_NEUTRON=1
- export DEVSTACK_GATE_TOPOLOGY="multinode"
- export DEVSTACK_GATE_TEMPEST_REGEX='(?=.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api)'
- export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1
- export PROJECTS="openstack/patrole $PROJECTS"
- export BRANCH_OVERRIDE=default
- if [ "$BRANCH_OVERRIDE" != "default" ] ; then
- export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE
- fi
- cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh
- ./safe-devstack-vm-gate-wrap.sh
- executable: /bin/bash
- chdir: '{{ ansible_user_dir }}/workspace'
- environment: '{{ zuul | zuul_legacy_vars }}'