Browse Source

Use NeutronService helper instead of network wrapper

This change allows to use network context without admin user

Change-Id: Ia25148e08e33d80ea9d021d5e16f87153b902d94
changes/79/723879/31
Andrey Kurilin 3 months ago
parent
commit
4c207ae082
35 changed files with 1463 additions and 1883 deletions
  1. +6
    -0
      .zuul.d/zuul.yaml
  2. +7
    -0
      CHANGELOG.rst
  3. +25
    -2
      rally-jobs/basic-with-existing-users.yaml
  4. +2
    -15
      rally-jobs/neutron.yaml
  5. +0
    -859
      rally-jobs/rally-mos.yaml
  6. +1
    -1
      rally_openstack/common/osclients.py
  7. +30
    -14
      rally_openstack/common/services/network/neutron.py
  8. +6
    -1
      rally_openstack/common/wrappers/network.py
  9. +51
    -57
      rally_openstack/task/contexts/keystone/users.py
  10. +63
    -77
      rally_openstack/task/contexts/network/allow_ssh.py
  11. +55
    -31
      rally_openstack/task/contexts/network/networks.py
  12. +299
    -163
      rally_openstack/task/scenarios/neutron/network.py
  13. +25
    -0
      rally_openstack/task/scenarios/neutron/utils.py
  14. +6
    -9
      rally_openstack/task/scenarios/nova/servers.py
  15. +6
    -14
      rally_openstack/task/scenarios/vm/utils.py
  16. +21
    -12
      rally_openstack/verification/tempest/context.py
  17. +2
    -4
      samples/tasks/scenarios/neutron/create-and-update-networks.json
  18. +0
    -2
      samples/tasks/scenarios/neutron/create-and-update-networks.yaml
  19. +1
    -4
      samples/tasks/scenarios/neutron/create-and-update-ports.json
  20. +0
    -3
      samples/tasks/scenarios/neutron/create-and-update-ports.yaml
  21. +1
    -5
      samples/tasks/scenarios/neutron/create-and-update-routers.json
  22. +0
    -4
      samples/tasks/scenarios/neutron/create-and-update-routers.yaml
  23. +1
    -4
      samples/tasks/scenarios/neutron/create-and-update-subnets.json
  24. +0
    -3
      samples/tasks/scenarios/neutron/create-and-update-subnets.yaml
  25. +0
    -4
      tasks/openstack/scenario/neutron.yaml
  26. +1
    -1
      tests/ci/cover.sh
  27. +4
    -3
      tests/unit/common/wrappers/test_network.py
  28. +43
    -67
      tests/unit/task/contexts/keystone/test_users.py
  29. +88
    -80
      tests/unit/task/contexts/network/test_allow_ssh.py
  30. +123
    -63
      tests/unit/task/contexts/network/test_network.py
  31. +533
    -332
      tests/unit/task/scenarios/neutron/test_network.py
  32. +2
    -0
      tests/unit/task/scenarios/neutron/test_utils.py
  33. +26
    -15
      tests/unit/task/scenarios/nova/test_servers.py
  34. +16
    -17
      tests/unit/task/scenarios/vm/test_utils.py
  35. +19
    -17
      tests/unit/verification/tempest/test_context.py

+ 6
- 0
.zuul.d/zuul.yaml View File

@@ -58,6 +58,9 @@
- .zuul.d/zuul.yaml
- rally-jobs/neutron-trunk.yaml
- rally_openstack/common/osclients.py
- rally_openstack/common/services/network
- rally_openstack/task/cleanup/resources.py
- rally_openstack/task/contexts/network
- rally_openstack/task/scenarios/neutron/trunk.py
- rally_openstack/task/scenarios/neutron/network.py
- tests/ci/playbooks
@@ -105,6 +108,9 @@
files:
- rally-jobs/neutron-trunk.yaml
- rally_openstack/common/osclients.py
- rally_openstack/common/services/network
- rally_openstack/task/cleanup/resources.py
- rally_openstack/task/contexts/network
- rally_openstack/task/scenarios/neutron/trunk.py
- rally_openstack/task/scenarios/neutron/network.py
- tests/ci/playbooks


+ 7
- 0
CHANGELOG.rst View File

@@ -26,9 +26,16 @@ Changed
image changed from /rally/xrally_opentstack to /rally/xrally_openstack
(there was a typo in work openstack)

* *network@openstack* context does not require admin credentials anymore and
work with regular users as well

Fixed
~~~~~

* Some neutron scenarios accepted *name* parameter for create or update actions
on various entities. The value of the parameter was always ignored, but
anyway it gave wrong assumption.

* [verification component] Make config parser case sensitivity in
TempestContext and TempestConfigfileManager.



+ 25
- 2
rally-jobs/basic-with-existing-users.yaml View File

@@ -78,8 +78,7 @@
workloads:
-
scenario:
NeutronNetworks.create_and_list_networks:
network_create_args:
NeutronNetworks.create_and_list_networks: {}
runner:
constant:
times: 2
@@ -92,6 +91,8 @@
NeutronNetworks.create_and_list_subnets:
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
contexts:
network: {}
runner:
constant:
times: 2
@@ -111,3 +112,25 @@
sla:
failure_rate:
max: 0

- title: Test VMTask scenario
workloads:
-
scenario:
VMTasks.dd_load_test:
flavor:
name: "m1.tiny"
image:
name: {{image_name}}
floating_network: "public"
force_delete: false
username: "cirros"
contexts:
network: {}
runner:
constant:
times: 2
concurrency: 2
sla:
failure_rate:
max: 0

+ 2
- 15
rally-jobs/neutron.yaml View File

@@ -89,8 +89,8 @@
NeutronNetworks.create_and_list_subnets:
-
args:
network_create_args:
subnet_create_args:
network_create_args: {}
subnet_create_args: {}
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
runner:
@@ -113,8 +113,6 @@
NeutronNetworks.create_and_show_subnets:
-
args:
network_create_args:
subnet_create_args:
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
runner:
@@ -316,11 +314,8 @@
NeutronNetworks.create_and_list_routers:
-
args:
network_create_args:
subnet_create_args:
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
router_create_args:
runner:
type: "constant"
times: {{smoke or 8}}
@@ -362,8 +357,6 @@
NeutronNetworks.create_and_list_ports:
-
args:
network_create_args:
port_create_args:
ports_per_network: 4
runner:
type: "constant"
@@ -403,8 +396,6 @@
NeutronNetworks.create_and_show_ports:
-
args:
network_create_args: {}
port_create_args: {}
ports_per_network: 2
runner:
type: "constant"
@@ -429,7 +420,6 @@
network_create_args: {}
network_update_args:
admin_state_up: False
name: "_updated"
runner:
type: "constant"
times: {{smoke or 8}}
@@ -454,7 +444,6 @@
subnets_per_network: 2
subnet_update_args:
enable_dhcp: False
name: "_subnet_updated"
runner:
type: "constant"
times: {{smoke or 8}}
@@ -482,7 +471,6 @@
router_create_args: {}
router_update_args:
admin_state_up: False
name: "_router_updated"
runner:
type: "constant"
times: {{smoke or 4}}
@@ -624,7 +612,6 @@
admin_state_up: False
device_id: "dummy_id"
device_owner: "dummy_owner"
name: "_port_updated"
runner:
type: "constant"
times: {{smoke or 10}}


+ 0
- 859
rally-jobs/rally-mos.yaml View File

@@ -1,859 +0,0 @@
---
{%- set cirros_image_url = "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img" %}
{%- set keystone_version = keystone_version|default("v2.0") %}
{% if keystone_version == "v2.0" %}

SaharaNodeGroupTemplates.create_and_list_node_group_templates:
-
args:
hadoop_version: "{{sahara_hadoop_version}}"
flavor:
name: "m1.small"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
api_versions:
sahara:
service_type: {{sahara_service_type}}
sla:
failure_rate:
max: 0

SaharaNodeGroupTemplates.create_delete_node_group_templates:
-
args:
hadoop_version: "{{sahara_hadoop_version}}"
flavor:
name: "m1.small"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
api_versions:
sahara:
service_type: {{sahara_service_type}}
sla:
failure_rate:
max: 0

KeystoneBasic.create_and_list_tenants:
-
args: {}
runner:
type: "constant"
times: 1
concurrency: 1
sla:
failure_rate:
max: 0

KeystoneBasic.create_tenant:
-
args: {}
runner:
type: "constant"
times: 1
concurrency: 1
sla:
failure_rate:
max: 0

KeystoneBasic.create_tenant_with_users:
-
args:
users_per_tenant: 10
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
sla:
failure_rate:
max: 0

{% endif %}

KeystoneBasic.create_user:
-
args: {}
runner:
type: "constant"
times: 1
concurrency: 1
sla:
failure_rate:
max: 0

KeystoneBasic.create_delete_user:
-
args: {}
runner:
type: "constant"
times: 1
concurrency: 1
sla:
failure_rate:
max: 0

KeystoneBasic.create_and_list_users:
-
args: {}
runner:
type: "constant"
times: 1
concurrency: 1
sla:
failure_rate:
max: 0

HeatStacks.create_and_list_stack:
-
args:
template_path: "~/.rally/extra/default.yaml.template"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

HeatStacks.create_and_delete_stack:
-
args:
template_path: "~/.rally/extra/default.yaml.template"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Authenticate.keystone:
-
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Authenticate.validate_cinder:
-
args:
repetitions: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Authenticate.validate_glance:
-
args:
repetitions: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Authenticate.validate_heat:
-
args:
repetitions: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Authenticate.validate_nova:
-
args:
repetitions: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Quotas.cinder_update_and_delete:
-
args:
max_quota: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Quotas.cinder_update:
-
args:
max_quota: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Quotas.nova_update_and_delete:
-
args:
max_quota: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

Quotas.nova_update:
-
args:
max_quota: 1024
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

VMTasks.boot_runcommand_delete:
-
args:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
floating_network: "{{external_net}}"
use_floating_ip: true
command:
script_file: "~/.rally/extra/instance_test.sh"
interpreter: "/bin/sh"
username: "cirros"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
network: {}
sla:
failure_rate:
max: 0


NovaServers.boot_and_delete_server:
-
args:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

-
args:
auto_assign_nic: true
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
network:
start_cidr: "10.2.0.0/24"
networks_per_tenant: 2
sla:
failure_rate:
max: 0


NovaServers.boot_and_list_server:
-
args:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
detailed: True
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

NovaServers.list_servers:
-
args:
detailed: True
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
servers:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
servers_per_tenant: 1
sla:
failure_rate:
max: 0

NovaServers.boot_and_bounce_server:
-
args:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
actions:
-
hard_reboot: 1
-
stop_start: 1
-
rescue_unrescue: 1
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

NovaServers.boot_server:
-
args:
flavor:
name: "^ram64$"
image:
name: "TestVM|cirros.*uec"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
flavors:
-
name: "ram64"
ram: 64
sla:
failure_rate:
max: 0
-
args:
flavor:
name: "m1.tiny"
image:
name: "TestVM|cirros.*uec"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_list_networks:
-
args:
network_create_args:
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_list_subnets:
-
args:
network_create_args:
subnet_create_args:
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_list_routers:
-
args:
network_create_args:
subnet_create_args:
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
router_create_args:
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
router: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_list_ports:
-
args:
network_create_args:
port_create_args:
ports_per_network: 4
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
router: -1
port: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_update_networks:
-
args:
network_create_args: {}
network_update_args:
admin_state_up: False
name: "_updated"
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_update_subnets:
-
args:
network_create_args: {}
subnet_create_args: {}
subnet_cidr_start: "1.4.0.0/16"
subnets_per_network: 2
subnet_update_args:
enable_dhcp: False
name: "_subnet_updated"
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 5
users_per_tenant: 5
quotas:
neutron:
network: -1
subnet: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_update_routers:
-
args:
network_create_args: {}
subnet_create_args: {}
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
router_create_args: {}
router_update_args:
admin_state_up: False
name: "_router_updated"
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
router: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_update_ports:
-
args:
network_create_args: {}
port_create_args: {}
ports_per_network: 5
port_update_args:
admin_state_up: False
device_id: "dummy_id"
device_owner: "dummy_owner"
name: "_port_updated"
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
port: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_delete_networks:
-
args:
network_create_args: {}
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_delete_subnets:
-
args:
network_create_args: {}
subnet_create_args: {}
subnet_cidr_start: "1.1.0.0/30"
subnets_per_network: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
subnet: -1
sla:
failure_rate:
max: 0

NeutronNetworks.create_and_delete_ports:
-
args:
network_create_args: {}
port_create_args: {}
ports_per_network: 10
runner:
type: "constant"
times: 1
concurrency: 1
context:
network: {}
users:
tenants: 1
users_per_tenant: 1
quotas:
neutron:
network: -1
port: -1
sla:
failure_rate:
max: 0

CinderVolumes.create_and_upload_volume_to_image:
-
args:
size: 1
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

CinderVolumes.create_volume_backup:
-
args:
size: 1
do_delete: True
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

CinderVolumes.create_and_restore_volume_backup:
-
args:
size: 1
do_delete: True
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

CinderVolumes.create_and_list_volume_backups:
-
args:
size: 1
detailed: True
do_delete: True
runner:
type: "constant"
times: 2
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

VMTasks.runcommand_heat:
-
args:
workload:
resource: ["rally.plugins.workload", "siege.py"]
username: "fedora"
template: /home/rally/.rally/extra/workload/wordpress_heat_template.yaml
files:
wp-instances.yaml: /home/rally/.rally/extra/workload/wp-instances.yaml
parameters:
wp_instances_count: 2
wp_instance_type: gig
instance_type: gig
wp_image: fedora
image: fedora
network_id: {{external_net_id}}
context:
users:
tenants: 1
users_per_tenant: 1
flavors:
- name: gig
ram: 1024
disk: 4
vcpus: 1
runner:
concurrency: 1
timeout: 3000
times: 1
type: constant
sla:
failure_rate:
max: 100

GlanceImages.create_and_update_image:
-
args:
image_location: "{{ cirros_image_url }}"
container_format: "bare"
disk_format: "qcow2"
runner:
type: "constant"
times: 4
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
api_versions:
glance:
version: 1
sla:
failure_rate:
max: 100

+ 1
- 1
rally_openstack/common/osclients.py View File

@@ -89,7 +89,7 @@ def configure(name, default_version=None, default_service_type=None,
variable is not specified, validation will assume that your client
doesn't allow to specify service type.
:param supported_versions: List of supported versions(If this variable is
not specified, `OSClients.validate_version` method will raise an
not specified, `OSClient.validate_version` method will raise an
exception that client doesn't support setting any versions. If this
logic is wrong for your client, you should override `validate_version`
in client object)


+ 30
- 14
rally_openstack/common/services/network/neutron.py View File

@@ -20,6 +20,7 @@ from rally import exceptions
from rally.task import atomic
from rally.task import service

from rally_openstack.common import consts
from rally_openstack.common.services.network import net_utils


@@ -271,17 +272,27 @@ class NeutronService(service.Service):
resp = self.client.show_network(network_id, **body)
return resp["network"]

def find_network(self, network_id_or_name):
def find_network(self, network_id_or_name, external=_NONE):
"""Find network by identifier (id or name)

:param network_id_or_name: Network ID or name
:param external: check target network is external or not
"""
network = None
for net in self.list_networks():
if network_id_or_name in (net["name"], net["id"]):
return net
raise exceptions.GetResourceFailure(
resource="network",
err=f"no name or id matches {network_id_or_name}")
network = net
break
if network is None:
raise exceptions.GetResourceFailure(
resource="network",
err=f"no name or id matches {network_id_or_name}")
if external:
if not network.get("router:external", False):
raise exceptions.NotFoundException(
f"Network '{network['name']} (id={network['id']})' is not "
f"external.")
return network

@atomic.action_timer("neutron.update_network")
@_create_network_arg_adapter()
@@ -579,7 +590,7 @@ class NeutronService(service.Service):
description=_NONE, discover_external_gw=False,
external_gateway_info=_NONE, distributed=_NONE, ha=_NONE,
availability_zone_hints=_NONE, service_type_id=_NONE,
flavor_id=_NONE):
flavor_id=_NONE, enable_snat=_NONE):
"""Create router.

:param project_id: The ID of the project that owns the resource. Only
@@ -605,12 +616,21 @@ class NeutronService(service.Service):
:param service_type_id: The ID of the service type associated with
the router.
:param flavor_id: The ID of the flavor associated with the router.
:param enable_snat: Whether to include `enable_snat: True` to
external_gateway_info or not. By default, it is enabled if a user
is admin and "ext-gw-mode" extension presents
"""

if external_gateway_info is _NONE and discover_external_gw:
for external_network in self.list_networks(router_external=True):
external_gateway_info = {"network_id": external_network["id"]}
if self.supports_extension("ext-gw-mode", silent=True):
if enable_snat is _NONE:
permission = self._clients.credential.permission
is_admin = permission == consts.EndpointPermission.ADMIN
if (self.supports_extension("ext-gw-mode", silent=True)
and is_admin):
external_gateway_info["enable_snat"] = True
elif enable_snat:
external_gateway_info["enable_snat"] = True
break

@@ -856,7 +876,8 @@ class NeutronService(service.Service):
self.client.delete_port(port["id"])
except neutron_exceptions.PortNotFoundClient:
# port is auto-removed
pass
return False
return True

@atomic.action_timer("neutron.list_ports")
def list_ports(self, network_id=_NONE, device_id=_NONE, device_owner=_NONE,
@@ -918,12 +939,7 @@ class NeutronService(service.Service):
if isinstance(floating_network, dict):
net_id = floating_network["id"]
elif floating_network:
network = self.find_network(floating_network)
if not network.get("router:external", False):
raise exceptions.NotFoundException(
f"Network '{network['name']} (id={network['id']})' is not "
f"external.")
net_id = network["id"]
net_id = self.find_network(floating_network, external=True)["id"]
else:
ext_networks = self.list_networks(router_external=True)
if not ext_networks:


+ 6
- 1
rally_openstack/common/wrappers/network.py View File

@@ -61,7 +61,7 @@ class NetworkWrapper(object, metaclass=abc.ABCMeta):
START_IPV6_CIDR = "dead:beaf::/64"
SERVICE_IMPL = None

def __init__(self, clients, owner, config=None, atomics=None):
def __init__(self, clients, owner, config=None):
"""Returns available network wrapper instance.

:param clients: rally.plugins.openstack.osclients.Clients instance
@@ -74,6 +74,7 @@ class NetworkWrapper(object, metaclass=abc.ABCMeta):
recognized, 'start_cidr' and 'start_ipv6_cidr'.
:returns: NetworkWrapper subclass instance
"""
self.clients = clients
if hasattr(clients, self.SERVICE_IMPL):
self.client = getattr(clients, self.SERVICE_IMPL)()
else:
@@ -123,6 +124,10 @@ class NeutronWrapper(NetworkWrapper):
def neutron(_self):
return self.client

@property
def credential(_self):
return self.clients.credential

self.neutron = neutron.NeutronService(
clients=_SingleClientWrapper(),
name_generator=self.owner.generate_random_name,


+ 51
- 57
rally_openstack/task/contexts/keystone/users.py View File

@@ -27,7 +27,7 @@ from rally_openstack.common import consts
from rally_openstack.common import credential
from rally_openstack.common import osclients
from rally_openstack.common.services.identity import identity
from rally_openstack.common.wrappers import network
from rally_openstack.common.services.network import neutron
from rally_openstack.task import context


@@ -35,8 +35,8 @@ LOG = logging.getLogger(__name__)

CONF = cfg.CONF

RESOURCE_MANAGEMENT_WORKERS_DESCR = ("The number of concurrent threads to use "
"for serving users context.")
RESOURCE_MANAGEMENT_WORKERS_DESCR = (
"The number of concurrent threads to use for serving users context.")
PROJECT_DOMAIN_DESCR = "ID of domain in which projects will be created."
USER_DOMAIN_DESCR = "ID of domain in which users will be created."

@@ -135,30 +135,6 @@ class UserGenerator(context.OpenStackContext):
for key, value in self.DEFAULT_FOR_NEW_USERS.items():
self.config.setdefault(key, value)

def _remove_default_security_group(self):
"""Delete default security group for tenants."""
clients = osclients.Clients(self.credential)

if consts.Service.NEUTRON not in clients.services().values():
return

use_sg, msg = network.wrap(clients, self).supports_extension(
"security-group")
if not use_sg:
LOG.debug("Security group context is disabled: %s" % msg)
return

for user, tenant_id in self._iterate_per_tenants():
with logging.ExceptionLogger(
LOG, "Unable to delete default security group"):
uclients = osclients.Clients(user["credential"])
security_groups = uclients.neutron()\
.list_security_groups(tenant_id=tenant_id)
default = [sg for sg in security_groups["security_groups"]
if sg["name"] == "default"]
if default:
clients.neutron().delete_security_group(default[0]["id"])

def _create_tenants(self, threads):
tenants = collections.deque()

@@ -237,36 +213,6 @@ class UserGenerator(context.OpenStackContext):
broker.run(publish, consume, threads)
return list(users)

def _get_consumer_for_deletion(self, func_name):
def consume(cache, resource_id):
if "client" not in cache:
clients = osclients.Clients(self.credential)
cache["client"] = identity.Identity(clients)
getattr(cache["client"], func_name)(resource_id)
return consume

def _delete_tenants(self):
threads = self.config["resource_management_workers"]

def publish(queue):
for tenant_id in self.context["tenants"]:
queue.append(tenant_id)

broker.run(publish, self._get_consumer_for_deletion("delete_project"),
threads)
self.context["tenants"] = {}

def _delete_users(self):
threads = self.config["resource_management_workers"]

def publish(queue):
for user in self.context["users"]:
queue.append(user["id"])

broker.run(publish, self._get_consumer_for_deletion("delete_user"),
threads)
self.context["users"] = []

def create_users(self):
"""Create tenants and users, using the broker pattern."""

@@ -331,6 +277,54 @@ class UserGenerator(context.OpenStackContext):
else:
self.create_users()

def _remove_default_security_group(self):
"""Delete default security group for tenants."""

admin_client = neutron.NeutronService(
clients=osclients.Clients(self.credential),
atomic_inst=self.atomic_actions()
)

if not admin_client.supports_extension("security-group", silent=True):
LOG.debug("Security group context is disabled.")
return

security_groups = admin_client.list_security_groups(name="default")
for security_group in security_groups:
if security_group["tenant_id"] not in self.context["tenants"]:
continue
admin_client.delete_security_group(security_group["id"])

def _get_consumer_for_deletion(self, func_name):
def consume(cache, resource_id):
if "client" not in cache:
clients = osclients.Clients(self.credential)
cache["client"] = identity.Identity(clients)
getattr(cache["client"], func_name)(resource_id)
return consume

def _delete_tenants(self):
threads = self.config["resource_management_workers"]

def publish(queue):
for tenant_id in self.context["tenants"]:
queue.append(tenant_id)

broker.run(publish, self._get_consumer_for_deletion("delete_project"),
threads)
self.context["tenants"] = {}

def _delete_users(self):
threads = self.config["resource_management_workers"]

def publish(queue):
for user in self.context["users"]:
queue.append(user["id"])

broker.run(publish, self._get_consumer_for_deletion("delete_user"),
threads)
self.context["users"] = []

def cleanup(self):
"""Delete tenants and users, using the broker pattern."""
if self.existing_users:


+ 63
- 77
rally_openstack/task/contexts/network/allow_ssh.py View File

@@ -16,8 +16,8 @@
from rally.common import logging
from rally.common import validation

from rally_openstack.common import osclients
from rally_openstack.common.wrappers import network
from rally_openstack.common.services.network import neutron
from rally_openstack.task.cleanup import manager as resource_manager
from rally_openstack.task import context


@@ -50,68 +50,33 @@ def _rule_to_key(rule):
"port_range_max",
"port_range_min",
"protocol",
"remote_ip_prefix",
"security_group_id"
"remote_ip_prefix"
]
return "_".join([_normalize_rule_value(x, rule.get(x))
for x in comparison_keys])


def _prepare_open_secgroup(credential, secgroup_name):
"""Generate secgroup allowing all tcp/udp/icmp access.

In order to run tests on instances it is necessary to have SSH access.
This function generates a secgroup which allows all tcp/udp/icmp access.

:param credential: clients credential
:param secgroup_name: security group name

:returns: dict with security group details
"""
neutron = osclients.Clients(credential).neutron()
security_groups = neutron.list_security_groups()["security_groups"]
rally_open = [sg for sg in security_groups if sg["name"] == secgroup_name]
if not rally_open:
descr = "Allow ssh access to VMs created by Rally"
rally_open = neutron.create_security_group(
{"security_group": {"name": secgroup_name,
"description": descr}})["security_group"]
else:
rally_open = rally_open[0]

rules_to_add = [
{
"protocol": "tcp",
"port_range_max": 65535,
"port_range_min": 1,
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress",
"security_group_id": rally_open["id"]
},
{
"protocol": "udp",
"port_range_max": 65535,
"port_range_min": 1,
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress",
"security_group_id": rally_open["id"]
},
{
"protocol": "icmp",
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress",
"security_group_id": rally_open["id"]
}
]

existing_rules = set(
_rule_to_key(r) for r in rally_open.get("security_group_rules", []))
for new_rule in rules_to_add:
if _rule_to_key(new_rule) not in existing_rules:
neutron.create_security_group_rule(
{"security_group_rule": new_rule})

return rally_open
_RULES_TO_ADD = [
{
"protocol": "tcp",
"port_range_max": 65535,
"port_range_min": 1,
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress"
},
{
"protocol": "udp",
"port_range_max": 65535,
"port_range_min": 1,
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress"
},
{
"protocol": "icmp",
"remote_ip_prefix": "0.0.0.0/0",
"direction": "ingress"
}
]


@validation.add("required_platform", platform="openstack", users=True)
@@ -120,27 +85,48 @@ class AllowSSH(context.OpenStackContext):
"""Sets up security groups for all users to access VM via SSH."""

def setup(self):
admin_or_user = (self.context.get("admin")
or self.context.get("users")[0])

net_wrapper = network.wrap(
osclients.Clients(admin_or_user["credential"]),
self, config=self.config)
use_sg, msg = net_wrapper.supports_extension("security-group")
if not use_sg:
LOG.info("Security group context is disabled: %s" % msg)
client = neutron.NeutronService(
clients=self.context["users"][0]["credential"].clients(),
name_generator=self.generate_random_name,
atomic_inst=self.atomic_actions()
)

if not client.supports_extension("security-group", silent=True):
LOG.info("Security group context is disabled.")
return

secgroup_name = self.generate_random_name()
secgroups_per_tenant = {}
for user, tenant_id in self._iterate_per_tenants():
client = neutron.NeutronService(
clients=user["credential"].clients(),
name_generator=self.generate_random_name,
atomic_inst=self.atomic_actions()
)
secgroup = client.create_security_group(
name=secgroup_name,
description="Allow ssh access to VMs created by Rally")
secgroups_per_tenant[tenant_id] = secgroup

existing_rules = set(
_rule_to_key(rule)
for rule in secgroup.get("security_group_rules", []))
for new_rule in _RULES_TO_ADD:
if _rule_to_key(new_rule) not in existing_rules:
secgroup.setdefault("security_group_rules", [])
secgroup["security_group_rules"].append(
client.create_security_group_rule(
security_group_id=secgroup["id"], **new_rule)
)

for user in self.context["users"]:
user["secgroup"] = _prepare_open_secgroup(user["credential"],
secgroup_name)
user["secgroup"] = secgroups_per_tenant[user["tenant_id"]]

def cleanup(self):
for user, tenant_id in self._iterate_per_tenants():
with logging.ExceptionLogger(
LOG,
"Unable to delete security group: %s."
% user["secgroup"]["name"]):
clients = osclients.Clients(user["credential"])
clients.neutron().delete_security_group(user["secgroup"]["id"])
resource_manager.cleanup(
names=["neutron.security_group"],
admin=self.context.get("admin"),
users=self.context["users"],
task_id=self.get_owner_id(),
superclass=self.__class__
)

+ 55
- 31
rally_openstack/task/contexts/network/networks.py View File

@@ -17,17 +17,15 @@ from rally.common import logging
from rally.common import validation

from rally_openstack.common import consts
from rally_openstack.common import osclients
from rally_openstack.common.wrappers import network as network_wrapper
from rally_openstack.common.services.network import neutron
from rally_openstack.task.cleanup import manager as resource_manager
from rally_openstack.task import context


LOG = logging.getLogger(__name__)


# NOTE(andreykurilin): admin is used only by cleanup
@validation.add("required_platform", platform="openstack", admin=True,
users=True)
@validation.add("required_platform", platform="openstack", users=True)
@context.configure(name="network", platform="openstack", order=350)
class Network(context.OpenStackContext):
"""Create networking resources.
@@ -67,7 +65,13 @@ class Network(context.OpenStackContext):
"type": "object",
"properties": {
"external": {
"type": "boolean"
"type": "boolean",
"description": "Create a new external router."
},
"enable_snat": {
"type": "boolean",
"description": "Whether to enable SNAT for a router "
"if there is following extension or not"
},
"external_gateway_info": {
"description": "The external gateway information .",
@@ -90,7 +94,6 @@ class Network(context.OpenStackContext):
"networks_per_tenant": 1,
"subnets_per_network": 1,
"network_create_args": {},
"dns_nameservers": None,
"router": {"external": True},
"dualstack": False
}
@@ -100,27 +103,47 @@ class Network(context.OpenStackContext):
# multithreading/multiprocessing, it is likely the
# sockets are left open. This problem is eliminated by
# creating a connection in setup and cleanup separately.
net_wrapper = network_wrapper.wrap(
osclients.Clients(self.context["admin"]["credential"]),
self,
config=self.config
)
kwargs = {}
if self.config["dns_nameservers"] is not None:
kwargs["dns_nameservers"] = self.config["dns_nameservers"]

for user, tenant_id in self._iterate_per_tenants():
self.context["tenants"][tenant_id]["networks"] = []
self.context["tenants"][tenant_id]["subnets"] = []

client = neutron.NeutronService(
user["credential"].clients(),
name_generator=self.generate_random_name,
atomic_inst=self.atomic_actions()
)
network_create_args = self.config["network_create_args"].copy()
subnet_create_args = {
"start_cidr": (self.config["start_cidr"]
if not self.config["dualstack"] else None)}
if "dns_nameservers" in self.config:
dns_nameservers = self.config["dns_nameservers"]
subnet_create_args["dns_nameservers"] = dns_nameservers

router_create_args = dict(self.config["router"] or {})
if not router_create_args:
# old behaviour - empty dict means no router create
router_create_args = None
elif "external" in router_create_args:
external = router_create_args.pop("external")
router_create_args["discover_external_gw"] = external

for i in range(self.config["networks_per_tenant"]):
network_create_args = self.config["network_create_args"].copy()
net_infra = net_wrapper._create_network_infrastructure(
tenant_id,
dualstack=self.config["dualstack"],
subnets_num=self.config["subnets_per_network"],

net_infra = client.create_network_topology(
network_create_args=network_create_args,
router_create_args=self.config["router"],
**kwargs)
subnet_create_args=subnet_create_args,
subnets_dualstack=self.config["dualstack"],
subnets_count=self.config["subnets_per_network"],
router_create_args=router_create_args)

if net_infra["routers"]:
router_id = net_infra["routers"][0]["id"]
else:
router_id = None
net_infra["network"]["router_id"] = router_id

self.context["tenants"][tenant_id]["networks"].append(
net_infra["network"]
)
@@ -129,12 +152,13 @@ class Network(context.OpenStackContext):
)

def cleanup(self):
net_wrapper = network_wrapper.wrap(
osclients.Clients(self.context["admin"]["credential"]),
self, config=self.config)
for tenant_id, tenant_ctx in self.context["tenants"].items():
for network in tenant_ctx.get("networks", []):
with logging.ExceptionLogger(
LOG,
"Failed to delete network for tenant %s" % tenant_id):
net_wrapper.delete_network(network)
resource_manager.cleanup(
names=[
"neutron.subnet", "neutron.network", "neutron.router",
"neutron.port"
],
admin=self.context.get("admin"),
users=self.context.get("users", []),
task_id=self.get_owner_id(),
superclass=self.__class__
)

+ 299
- 163
rally_openstack/task/scenarios/neutron/network.py View File

@@ -28,13 +28,16 @@ LOG = logging.getLogger(__name__)
"""Scenarios for Neutron."""


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@validation.add("required_platform", platform="openstack", users=True)
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_list_networks",
platform="openstack")
class CreateAndListNetworks(utils.NeutronScenario):
class CreateAndListNetworks(utils.NeutronBaseScenario):

def run(self, network_create_args=None):
"""Create a network and then list all networks.
@@ -49,17 +52,20 @@ class CreateAndListNetworks(utils.NeutronScenario):

:param network_create_args: dict, POST /v2.0/networks request options
"""
self._create_network(network_create_args or {})
self._list_networks()
self.neutron.create_network(**(network_create_args or {}))
self.neutron.list_networks()


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@validation.add("required_platform", platform="openstack", users=True)
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_show_network",
platform="openstack")
class CreateAndShowNetwork(utils.NeutronScenario):
class CreateAndShowNetwork(utils.NeutronBaseScenario):

def run(self, network_create_args=None):
"""Create a network and show network details.
@@ -68,17 +74,23 @@ class CreateAndShowNetwork(utils.NeutronScenario):

:param network_create_args: dict, POST /v2.0/networks request options
"""
network = self._create_network(network_create_args or {})
self._show_network(network)
network = self.neutron.create_network(**(network_create_args or {}))
self.neutron.get_network(network["id"])


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="network_update_args")
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@validation.add("required_platform", platform="openstack", users=True)
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_update_networks",
platform="openstack")
class CreateAndUpdateNetworks(utils.NeutronScenario):
class CreateAndUpdateNetworks(utils.NeutronBaseScenario):

def run(self, network_update_args, network_create_args=None):
"""Create and update a network.
@@ -88,16 +100,19 @@ class CreateAndUpdateNetworks(utils.NeutronScenario):
:param network_update_args: dict, PUT /v2.0/networks update request
:param network_create_args: dict, POST /v2.0/networks request options
"""
network = self._create_network(network_create_args or {})
self._update_network(network, network_update_args)
network = self.neutron.create_network(**(network_create_args or {}))
self.neutron.update_network(network["id"], **network_update_args)


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("required_services",
services=[consts.Service.NEUTRON])
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_delete_networks",
platform="openstack")
class CreateAndDeleteNetworks(utils.NeutronScenario):
class CreateAndDeleteNetworks(utils.NeutronBaseScenario):

def run(self, network_create_args=None):
"""Create and delete a network.
@@ -106,10 +121,16 @@ class CreateAndDeleteNetworks(utils.NeutronScenario):

:param network_create_args: dict, POST /v2.0/networks request options
"""
network = self._create_network(network_create_args or {})
self._delete_network(network["network"])
network = self.neutron.create_network(**(network_create_args or {}))
self.neutron.delete_network(network["id"])


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -118,7 +139,7 @@ class CreateAndDeleteNetworks(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_list_subnets",
platform="openstack")
class CreateAndListSubnets(utils.NeutronScenario):
class CreateAndListSubnets(utils.NeutronBaseScenario):

def run(self, network_create_args=None, subnet_create_args=None,
subnet_cidr_start=None, subnets_per_network=1):
@@ -133,12 +154,23 @@ class CreateAndListSubnets(utils.NeutronScenario):
:param subnet_cidr_start: str, start value for subnets CIDR
:param subnets_per_network: int, number of subnets for one network
"""
network = self._create_network(network_create_args or {})
self._create_subnets(network, subnet_create_args, subnet_cidr_start,
subnets_per_network)
self._list_subnets()


network = self.neutron.create_network(**(network_create_args or {}))
for _ in range(subnets_per_network):
self.neutron.create_subnet(network["id"],
start_cidr=subnet_cidr_start,
**(subnet_create_args or {}))
self.neutron.list_subnets()


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_update_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -147,7 +179,7 @@ class CreateAndListSubnets(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_update_subnets",
platform="openstack")
class CreateAndUpdateSubnets(utils.NeutronScenario):
class CreateAndUpdateSubnets(utils.NeutronBaseScenario):

def run(self, subnet_update_args, network_create_args=None,
subnet_create_args=None, subnet_cidr_start=None,
@@ -165,14 +197,24 @@ class CreateAndUpdateSubnets(utils.NeutronScenario):
:param subnet_cidr_start: str, start value for subnets CIDR
:param subnets_per_network: int, number of subnets for one network
"""
network = self._create_network(network_create_args or {})
subnets = self._create_subnets(network, subnet_create_args,
subnet_cidr_start, subnets_per_network)

network = self.neutron.create_network(**(network_create_args or {}))
subnets = []
for _ in range(subnets_per_network):
subnets.append(
self.neutron.create_subnet(
network["id"], start_cidr=subnet_cidr_start,
**(subnet_create_args or {}))
)
for subnet in subnets:
self._update_subnet(subnet, subnet_update_args)
self.neutron.update_subnet(subnet["id"], **subnet_update_args)


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -181,7 +223,7 @@ class CreateAndUpdateSubnets(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_show_subnets",
platform="openstack")
class CreateAndShowSubnets(utils.NeutronScenario):
class CreateAndShowSubnets(utils.NeutronBaseScenario):

def run(self, network_create_args=None,
subnet_create_args=None, subnet_cidr_start=None,
@@ -198,14 +240,24 @@ class CreateAndShowSubnets(utils.NeutronScenario):
:param subnet_cidr_start: str, start value for subnets CIDR
:param subnets_per_network: int, number of subnets for one network
"""
network = self._get_or_create_network(network_create_args)
subnets = self._create_subnets(network, subnet_create_args,
subnet_cidr_start, subnets_per_network)

network = self._get_or_create_network(**(network_create_args or {}))
subnets = []
for _ in range(subnets_per_network):
subnets.append(
self.neutron.create_subnet(
network["id"], start_cidr=subnet_cidr_start,
**(subnet_create_args or {}))
)
for subnet in subnets:
self._show_subnet(subnet)
self.neutron.get_subnet(subnet["id"])


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -213,7 +265,7 @@ class CreateAndShowSubnets(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_delete_subnets",
platform="openstack")
class CreateAndDeleteSubnets(utils.NeutronScenario):
class CreateAndDeleteSubnets(utils.NeutronBaseScenario):

def run(self, network_create_args=None, subnet_create_args=None,
subnet_cidr_start=None, subnets_per_network=1):
@@ -228,14 +280,27 @@ class CreateAndDeleteSubnets(utils.NeutronScenario):
:param subnet_cidr_start: str, start value for subnets CIDR
:param subnets_per_network: int, number of subnets for one network
"""
network = self._get_or_create_network(network_create_args)
subnets = self._create_subnets(network, subnet_create_args,
subnet_cidr_start, subnets_per_network)

network = self._get_or_create_network(**(network_create_args or {}))
subnets = []
for _ in range(subnets_per_network):
subnets.append(
self.neutron.create_subnet(
network["id"], start_cidr=subnet_cidr_start,
**(subnet_create_args or {}))
)
for subnet in subnets:
self._delete_subnet(subnet)


self.neutron.delete_subnet(subnet["id"])


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="router_create_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -244,7 +309,7 @@ class CreateAndDeleteSubnets(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_list_routers",
platform="openstack")
class CreateAndListRouters(utils.NeutronScenario):
class CreateAndListRouters(utils.NeutronBaseScenario):

def run(self, network_create_args=None, subnet_create_args=None,
subnet_cidr_start=None, subnets_per_network=1,
@@ -261,12 +326,28 @@ class CreateAndListRouters(utils.NeutronScenario):
:param subnets_per_network: int, number of subnets for one network
:param router_create_args: dict, POST /v2.0/routers request options
"""
self._create_network_structure(network_create_args, subnet_create_args,
subnet_cidr_start, subnets_per_network,
router_create_args)
self._list_routers()


subnet_create_args = dict(subnet_create_args or {})
subnet_create_args["start_cidr"] = subnet_cidr_start

self.neutron.create_network_topology(
network_create_args=(network_create_args or {}),
router_create_args=(router_create_args or {}),
router_per_subnet=True,
subnet_create_args=subnet_create_args,
subnets_count=subnets_per_network
)
self.neutron.list_routers()


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="router_create_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services", services=[consts.Service.NEUTRON])
@@ -274,7 +355,7 @@ class CreateAndListRouters(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_show_routers",
platform="openstack")
class CreateAndShowRouters(utils.NeutronScenario):
class CreateAndShowRouters(utils.NeutronBaseScenario):

def run(self, network_create_args=None, subnet_create_args=None,
subnet_cidr_start=None, subnets_per_network=1,
@@ -291,14 +372,33 @@ class CreateAndShowRouters(utils.NeutronScenario):
:param subnets_per_network: int, number of subnets for each network
:param router_create_args: dict, POST /v2.0/routers request options
"""
network, subnets, routers = self._create_network_structure(
network_create_args, subnet_create_args, subnet_cidr_start,
subnets_per_network, router_create_args)

for router in routers:
self._show_router(router)


subnet_create_args = dict(subnet_create_args or {})
subnet_create_args["start_cidr"] = subnet_cidr_start

net_topo = self.neutron.create_network_topology(
network_create_args=(network_create_args or {}),
router_create_args=(router_create_args or {}),
router_per_subnet=True,
subnet_create_args=subnet_create_args,
subnets_count=subnets_per_network
)

for router in net_topo["routers"]:
self.neutron.get_router(router["id"])


@validation.add("restricted_parameters",
param_names="name",
subdict="network_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="subnet_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="router_create_args")
@validation.add("restricted_parameters",
param_names="name",
subdict="router_update_args")
@validation.add("number", param_name="subnets_per_network", minval=1,
integer_only=True)
@validation.add("required_services",
@@ -306,7 +406,7 @@ class CreateAndShowRouters(utils.NeutronScenario):
@scenario.configure(context={"cleanup@openstack": ["neutron"]},
name="NeutronNetworks.create_and_update_routers",
platform="openstack")
class CreateAndUpdateRouters(utils.NeutronScenario):
class CreateAndUpdateRouters(utils.NeutronBaseScenario):

def run(self, router_update_args, network_create_args=None,
subnet_create_args=None, subnet_cidr_start=None,
@@ -324,14 +424,30 @@ class CreateAndUpdateRouters(utils.NeutronScenario):
:param subnets_per_network: int, number of subnets for one network
:param router_create_args: dict, POST /v2.0/routers request options
"""
network, subnets, routers = self._create_network_structure(
network_create_args, subnet_create_args, subnet_cidr_start,
subnets_per_network, router_create_args)

for router in routers:
self._update_router(router, router_update_args)