Add tenant network creation to account creation script

The script will now create a tenant network for each account in the same
way as the isolated creds code creates networks. In this case we always
create all network resource options since each test account could run a test
that requires any one of them. The accounts will only be created if neutron
is available and the user did not set auth.create_isolated_networks to
False.

Partially implements: blueprint test-accounts-continued

Change-Id: Id3b626b66f797e32e18f4d1771561a1db5ecd26c
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 0a48b8d..6fc5fcc 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -15,6 +15,7 @@
 #    under the License.
 
 import argparse
+import netaddr
 import os
 
 from oslo_log import log as logging
@@ -23,6 +24,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.services.identity.v2.json import identity_client
+from tempest.services.network.json import network_client
 import tempest_lib.auth
 from tempest_lib.common.utils import data_utils
 import tempest_lib.exceptions
@@ -37,7 +39,7 @@
     LOG = logging.getLogger(__name__)
 
 
-def keystone_admin(opts):
+def get_admin_clients(opts):
     _creds = tempest_lib.auth.KeystoneV2Credentials(
         username=opts.os_username,
         password=opts.os_password,
@@ -58,18 +60,28 @@
         'build_interval': CONF.compute.build_interval,
         'build_timeout': CONF.compute.build_timeout
     }
-    return identity_client.IdentityClientJSON(
+    identity_admin = identity_client.IdentityClientJSON(
         _auth,
         CONF.identity.catalog_type,
         CONF.identity.region,
         endpoint_type='adminURL',
         **params
     )
+    network_admin = None
+    if (CONF.service_available.neutron and
+        CONF.auth.create_isolated_networks):
+        network_admin = network_client.NetworkClientJSON(
+            _auth,
+            CONF.network.catalog_type,
+            CONF.network.region or CONF.identity.region,
+            endpoint_type='adminURL',
+            **params)
+    return identity_admin, network_admin
 
 
 def create_resources(opts, resources):
-    admin = keystone_admin(opts)
-    roles = admin.list_roles()
+    identity_admin, network_admin = get_admin_clients(opts)
+    roles = identity_admin.list_roles()
     for u in resources['users']:
         u['role_ids'] = []
         for r in u.get('roles', ()):
@@ -80,24 +92,24 @@
                 raise exceptions.TempestException(
                     "Role: %s - doesn't exist" % r
                 )
-    existing = [x['name'] for x in admin.list_tenants()]
+    existing = [x['name'] for x in identity_admin.list_tenants()]
     for tenant in resources['tenants']:
         if tenant not in existing:
-            admin.create_tenant(tenant)
+            identity_admin.create_tenant(tenant)
         else:
             LOG.warn("Tenant '%s' already exists in this environment" % tenant)
     LOG.info('Tenants created')
     for u in resources['users']:
         try:
-            tenant = admin.get_tenant_by_name(u['tenant'])
+            tenant = identity_admin.get_tenant_by_name(u['tenant'])
         except tempest_lib.exceptions.NotFound:
             LOG.error("Tenant: %s - not found" % u['tenant'])
             continue
         while True:
             try:
-                admin.get_user_by_username(tenant['id'], u['name'])
+                identity_admin.get_user_by_username(tenant['id'], u['name'])
             except tempest_lib.exceptions.NotFound:
-                admin.create_user(
+                identity_admin.create_user(
                     u['name'], u['pass'], tenant['id'],
                     "%s@%s" % (u['name'], tenant['id']),
                     enabled=True)
@@ -108,21 +120,29 @@
                 u['name'] = random_user_name(opts.tag, u['prefix'])
 
     LOG.info('Users created')
+    if network_admin:
+        for u in resources['users']:
+            tenant = identity_admin.get_tenant_by_name(u['tenant'])
+            network_name = create_network_resources(network_admin,
+                                                    tenant['id'],
+                                                    u['name'])
+            u['network'] = network_name
+        LOG.info('Networks created')
     for u in resources['users']:
         try:
-            tenant = admin.get_tenant_by_name(u['tenant'])
+            tenant = identity_admin.get_tenant_by_name(u['tenant'])
         except tempest_lib.exceptions.NotFound:
             LOG.error("Tenant: %s - not found" % u['tenant'])
             continue
         try:
-            user = admin.get_user_by_username(tenant['id'],
-                                              u['name'])
+            user = identity_admin.get_user_by_username(tenant['id'],
+                                                       u['name'])
         except tempest_lib.exceptions.NotFound:
             LOG.error("User: %s - not found" % u['user'])
             continue
         for r in u['role_ids']:
             try:
-                admin.assign_user_role(tenant['id'], user['id'], r)
+                identity_admin.assign_user_role(tenant['id'], user['id'], r)
             except tempest_lib.exceptions.Conflict:
                 # don't care if it's already assigned
                 pass
@@ -130,6 +150,57 @@
     LOG.info('Resources deployed successfully!')
 
 
+def create_network_resources(network_admin_client, tenant_id, name):
+
+    def _create_network(name):
+        resp_body = network_admin_client.create_network(
+            name=name, tenant_id=tenant_id)
+        return resp_body['network']
+
+    def _create_subnet(subnet_name, network_id):
+        base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+        mask_bits = CONF.network.tenant_network_mask_bits
+        for subnet_cidr in base_cidr.subnet(mask_bits):
+            try:
+                resp_body = network_admin_client.\
+                    create_subnet(
+                        network_id=network_id, cidr=str(subnet_cidr),
+                        name=subnet_name,
+                        tenant_id=tenant_id,
+                        enable_dhcp=True,
+                        ip_version=4)
+                break
+            except tempest_lib.exceptions.BadRequest as e:
+                if 'overlaps with another subnet' not in str(e):
+                    raise
+        else:
+            message = 'Available CIDR for subnet creation could not be found'
+            raise Exception(message)
+        return resp_body['subnet']
+
+    def _create_router(router_name):
+        external_net_id = dict(
+            network_id=CONF.network.public_network_id)
+        resp_body = network_admin_client.create_router(
+            router_name,
+            external_gateway_info=external_net_id,
+            tenant_id=tenant_id)
+        return resp_body['router']
+
+    def _add_router_interface(router_id, subnet_id):
+        network_admin_client.add_router_interface_with_subnet_id(
+            router_id, subnet_id)
+
+    network_name = name + "-network"
+    network = _create_network(network_name)
+    subnet_name = name + "-subnet"
+    subnet = _create_subnet(subnet_name, network['id'])
+    router_name = name + "-router"
+    router = _create_router(router_name)
+    _add_router_interface(router['id'], subnet['id'])
+    return network_name
+
+
 def random_user_name(tag, prefix):
     if tag:
         return data_utils.rand_name('-'.join((tag, prefix)))
@@ -185,12 +256,15 @@
 def dump_accounts(opts, resources):
     accounts = []
     for user in resources['users']:
-        accounts.append({
+        account = {
             'username': user['name'],
             'tenant_name': user['tenant'],
             'password': user['pass'],
             'roles': user['roles']
-        })
+        }
+        if 'network' in user:
+            account['resources'] = {'network': user['network']}
+        accounts.append(account)
     if os.path.exists(opts.accounts):
         os.rename(opts.accounts, '.'.join((opts.accounts, 'bak')))
     with open(opts.accounts, 'w') as f: