Preliminary version of Kloudbuster

Openstack resources creation

Change-Id: I0d1dfe0c8591a551ebf739aa3e77f67a2f68cd67
This commit is contained in:
AJAY KALAMBUR 2015-03-17 13:01:02 -07:00
parent e6d50a7ded
commit e391ad79e3
8 changed files with 926 additions and 0 deletions

8
scale/README Normal file
View File

@ -0,0 +1,8 @@
This is for VMTP scale testing
This is work in progress for now
The idea is to be able to
1. Create tenant and users to load the cloud
2. Create routers within a User in a tenant
3. Create N networks per router
4. Create N VMs per network
5. Clean up all resources by default (Provide ability to avoid cleanup)

188
scale/base_compute.py Normal file
View File

@ -0,0 +1,188 @@
# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import time
class BaseCompute(object):
"""
The Base class for nova compute resources
1. Creates virtual machines with specific configs
"""
def __init__(self, nova_client, user_name):
self.novaclient = nova_client
self.user_name = user_name
self.instance = None
self.fip = None
self.fip_ip = None
# Create a server instance with associated
# security group, keypair with a provided public key
def create_server(self, vmname, image_name, flavor_type, keyname,
nic, sec_group, public_key_file,
avail_zone=None, user_data=None,
config_drive=None,
retry_count=100):
"""
Create a VM instance given following parameters
1. VM Name
2. Image Name
3. Flavor name
4. key pair name
5. Security group instance
6. Optional parameters: availability zone, user data, config drive
"""
# Get the image id and flavor id from their logical names
image = self.find_image(image_name)
flavor_type = self.find_flavor(flavor_type)
# Also attach the created security group for the test
instance = self.novaclient.servers.create(name=vmname,
image=image,
flavor=flavor_type,
key_name=keyname,
nics=nic,
availability_zone=avail_zone,
userdata=user_data,
config_drive=config_drive,
security_groups=[sec_group.id])
flag_exist = self.find_server(vmname, retry_count)
if flag_exist:
self.instance = instance
# Returns True if server is present false if not.
# Retry for a few seconds since after VM creation sometimes
# it takes a while to show up
def find_server(self, vmname, retry_count):
for _ in range(retry_count):
servers_list = self.get_server_list()
for server in servers_list:
if server.name == vmname and server.status == "ACTIVE":
return True
time.sleep(2)
print "[%s] VM not found, after %d attempts" % (vmname, retry_count)
return False
def get_server_list(self):
servers_list = self.novaclient.servers.list()
return servers_list
def delete_server(self):
# First delete the instance
self.novaclient.servers.delete(self.instance)
def find_image(self, image_name):
"""
Given a image name return the image id
"""
try:
image = self.novaclient.images.find(name=image_name)
return image
except Exception:
return None
def find_flavor(self, flavor_type):
"""
Given a named flavor return the flavor
"""
flavor = self.novaclient.flavors.find(name=flavor_type)
return flavor
class SecGroup(object):
def __init__(self, novaclient):
self.secgroup = None
self.secgroup_name = None
self.novaclient = novaclient
def create_secgroup_with_rules(self, group_name):
group = self.novaclient.security_groups.create(name=group_name,
description="Test sec group")
# Allow ping traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="icmp",
from_port=-1,
to_port=-1)
# Allow SSH traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=22,
to_port=22)
# Allow HTTP traffic
self.novaclient.security_group_rules.create(group.id,
ip_protocol="tcp",
from_port=80,
to_port=80)
self.secgroup = group
self.secgroup_name = group_name
def delete_secgroup(self):
"""
Delete the security group
Sometimes this maybe in use if instance is just deleted
Add a retry mechanism
"""
print "Deleting secgroup %s" % (self.secgroup)
for retry_count in range(10):
try:
self.novaclient.security_groups.delete(self.secgroup)
break
except Exception:
print "Security group %s in use retry count:%d" % (self.secgroup_name, retry_count)
time.sleep(4)
class KeyPair(object):
def __init__(self, novaclient):
self.keypair = None
self.keypair_name = None
self.novaclient = novaclient
def add_public_key(self, name, public_key_file):
"""
Add the KloudBuster public key to openstack
"""
public_key = None
try:
with open(os.path.expanduser(public_key_file)) as pkf:
public_key = pkf.read()
except IOError as exc:
print 'ERROR: Cannot open public key file %s: %s' % \
(public_key_file, exc)
print 'Adding public key %s' % (name)
keypair = self.novaclient.keypairs.create(name, public_key)
self.keypair = keypair
self.keypair_name = name
def remove_public_key(self):
"""
Remove the keypair created by KloudBuster
"""
self.novaclient.keypairs.delete(self.keypair)

289
scale/base_network.py Normal file
View File

@ -0,0 +1,289 @@
# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import base_compute
import netaddr
from neutronclient.common.exceptions import NetworkInUseClient
# Global CIDR shared by all objects of this class
# Enables each network to get a unique CIDR
START_CIDR = "1.0.0.0/16"
cidr = START_CIDR
def create_floating_ip(neutron_client, ext_net):
"""
Function that creates a floating ip and returns it
Accepts the neutron client and ext_net
Module level function since this is not associated with a
specific network instance
"""
body = {
"floatingip": {
"floating_network_id": ext_net['id']
}
}
fip = neutron_client.create_floatingip(body)
return fip
def delete_floating_ip(neutron_client, fip):
"""
Deletes the floating ip
Module level function since this operation
is not associated with a network
"""
neutron_client.delete_floatingip(fip)
def find_external_network(neutron_client):
"""
Find the external network
and return it
If no external network is found return None
"""
networks = neutron_client.list_networks()['networks']
for network in networks:
if network['router:external']:
return network
print "No external network found!!!"
return None
class BaseNetwork(object):
"""
The Base class for neutron network operations
1. Creates networks with 1 subnet inside each network
2. Increments a global CIDR for all network instances
3. Deletes all networks on completion
4. Also interacts with the compute class for instances
"""
def __init__(self, neutron_client, nova_client, user_name):
"""
Store the neutron client
User name for this network
and network object
"""
self.neutron_client = neutron_client
self.nova_client = nova_client
self.user_name = user_name
self.network = None
self.instance_list = []
self.secgroup_list = []
self.keypair_list = []
def create_compute_resources(self, config_scale):
"""
Creates the compute resources includes the following resources
1. VM instances
2. Security groups
3. Keypairs
"""
# Create the security groups first
for secgroup_count in range(config_scale.secgroups_per_network):
secgroup_instance = base_compute.SecGroup(self.nova_client)
self.secgroup_list.append(secgroup_instance)
secgroup_name = "kloudbuster_secgroup" + "_" + self.network['id'] + str(secgroup_count)
secgroup_instance.create_secgroup_with_rules(secgroup_name)
# Create the keypair list
for keypair_count in range(config_scale.keypairs_per_network):
keypair_instance = base_compute.KeyPair(self.nova_client)
self.keypair_list.append(keypair_instance)
keypair_name = "kloudbuster_keypair" + "_" + self.network['id'] + str(keypair_count)
keypair_instance.add_public_key(keypair_name, config_scale.public_key_file)
# Create the required number of VMs
# Create the VMs on specified network, first keypair, first secgroup
external_network = find_external_network(self.neutron_client)
print "Creating Virtual machines for user %s" % (self.user_name)
for instance_count in range(config_scale.vms_per_network):
nova_instance = base_compute.BaseCompute(self.nova_client, self.user_name)
self.instance_list.append(nova_instance)
vm_name = "kloudbuster_vm" + "_" + self.network['id'] + str(instance_count)
nic_used = [{'net-id': self.network['id']}]
nova_instance.create_server(vm_name, config_scale.image_name,
config_scale.flavor_type,
self.keypair_list[0].keypair_name,
nic_used,
self.secgroup_list[0].secgroup,
config_scale.public_key_file,
None,
None,
None)
# Create the floating ip for the instance store it and the ip address in instance object
nova_instance.fip = create_floating_ip(self.neutron_client, external_network)
nova_instance.fip_ip = nova_instance.fip['floatingip']['floating_ip_address']
# Associate the floating ip with this instance
nova_instance.instance.add_floating_ip(nova_instance.fip_ip)
def delete_compute_resources(self):
"""
Deletes the compute resources
Security groups,keypairs and instances
"""
# Delete the instances first
for instance in self.instance_list:
instance.delete_server()
delete_floating_ip(self.neutron_client, instance.fip['floatingip']['id'])
# Delete all security groups
for secgroup_instance in self.secgroup_list:
secgroup_instance.delete_secgroup()
# Delete all keypairs
for keypair_instance in self.keypair_list:
keypair_instance.remove_public_key()
def create_network_and_subnet(self, network_name):
"""
Create a network with 1 subnet inside it
"""
subnet_name = "kloudbuster_subnet" + network_name
body = {
'network': {
'name': network_name,
'admin_state_up': True
}
}
self.network = self.neutron_client.create_network(body)['network']
# Now create the subnet inside this network support ipv6 in future
body = {
'subnet': {
'name': subnet_name,
'cidr': self.generate_cidr(),
'network_id': self.network['id'],
'enable_dhcp': True,
'ip_version': 4
}
}
subnet = self.neutron_client.create_subnet(body)['subnet']
# add subnet id to the network dict since it has just been added
self.network['subnets'] = [subnet['id']]
def generate_cidr(self):
"""Generate next CIDR for network or subnet, without IP overlapping.
"""
global cidr
cidr = str(netaddr.IPNetwork(cidr).next())
return cidr
def delete_network(self):
"""
Deletes the network and associated subnet
retry the deletion since network may be in use
"""
for _ in range(1, 5):
try:
self.neutron_client.delete_network(self.network['id'])
break
except NetworkInUseClient:
time.sleep(1)
class Router(object):
"""
Router class to create a new routers
Supports addition and deletion
of network interfaces to router
"""
def __init__(self, neutron_client, nova_client, user_name):
self.neutron_client = neutron_client
self.nova_client = nova_client
self.router = None
self.user_name = user_name
# Stores the list of networks
self.network_list = []
def create_network_resources(self, config_scale):
"""
Creates the required number of networks per router
Also triggers the creation of compute resources inside each
network
"""
for network_count in range(config_scale.networks_per_router):
network_instance = BaseNetwork(self.neutron_client, self.nova_client, self.user_name)
self.network_list.append(network_instance)
# Create the network and subnet
network_name = "kloudbuster_network" + "_" + str(network_count)
network_instance.create_network_and_subnet(network_name)
# Attach the created network to router interface
self.attach_router_interface(network_instance)
# Create the compute resources in the network
network_instance.create_compute_resources(config_scale)
def delete_network_resources(self):
"""
Delete all network and compute resources
associated with a router
"""
for network in self.network_list:
# Now delete the compute resources and the network resources
network.delete_compute_resources()
self.remove_router_interface(network)
network.delete_network()
def create_router(self, router_name, ext_net):
"""
Create the router and attach it to
external network
"""
body = {
"router": {
"name": router_name,
"admin_state_up": True,
"external_gateway_info": {
"network_id": ext_net['id']
}
}
}
self.router = self.neutron_client.create_router(body)
return self.router['router']
def delete_router(self):
"""
Delete the router
Also delete the networks attached to this router
"""
# Delete the network resources first and than delete the router itself
self.delete_network_resources()
self.neutron_client.delete_router(self.router['router']['id'])
def attach_router_interface(self, network_instance):
"""
Attach a network interface to the router
"""
body = {
'subnet_id': network_instance.network['subnets'][0]
}
self.neutron_client.add_interface_router(self.router['router']['id'], body)
def remove_router_interface(self, network_instance):
"""
Remove the network interface from router
"""
body = {
'subnet_id': network_instance.network['subnets'][0]
}
self.neutron_client.remove_interface_router(self.router['router']['id'], body)

31
scale/cfg.scale.yaml Normal file
View File

@ -0,0 +1,31 @@
# KloudBuster Default configuration file
# Number of tenants to be created on the cloud
number_tenants: 1
# Number of Users to be created inside the tenant
users_per_tenant: 1
# Number of networks to be created within the context of each Router
# Assumes 1 subnet per network
networks_per_router: 2
# Number of routers to be created within the context of each User
# For now support only 1 router per user
routers_per_user: 1
# Number of VM instances to be created within the context of each User
vms_per_network: 1
# Number of security groups per user
secgroups_per_network: 1
# Number of keypairs per user
keypairs_per_network: 1
#Configs that remain constant
keystone_admin_role: "admin"
cleanup_resources : True
public_key_file : '../ssh/id_rsa.pub'
image_name : 'Ubuntu Server 14.04'
flavor_type: 'm1.small'

110
scale/credentials.py Normal file
View File

@ -0,0 +1,110 @@
# Copyright 2014 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Module for credentials in Openstack
import getpass
import os
import re
class Credentials(object):
def get_credentials(self):
dct = {}
dct['username'] = self.rc_username
dct['password'] = self.rc_password
dct['auth_url'] = self.rc_auth_url
dct['tenant_name'] = self.rc_tenant_name
return dct
def get_nova_credentials(self):
dct = {}
dct['username'] = self.rc_username
dct['api_key'] = self.rc_password
dct['auth_url'] = self.rc_auth_url
dct['project_id'] = self.rc_tenant_name
return dct
def get_nova_credentials_v2(self):
dct = self.get_nova_credentials()
dct['version'] = 2
return dct
#
# Read a openrc file and take care of the password
# The 2 args are passed from the command line and can be None
#
def __init__(self, openrc_file, pwd, no_env):
self.rc_password = None
self.rc_username = None
self.rc_tenant_name = None
self.rc_auth_url = None
success = True
if openrc_file:
if os.path.exists(openrc_file):
export_re = re.compile('export OS_([A-Z_]*)="?(.*)')
for line in open(openrc_file):
line = line.strip()
mstr = export_re.match(line)
if mstr:
# get rif of posible trailing double quote
# the first one was removed by the re
name = mstr.group(1)
value = mstr.group(2)
if value.endswith('"'):
value = value[:-1]
# get rid of password assignment
# echo "Please enter your OpenStack Password: "
# read -sr OS_PASSWORD_INPUT
# export OS_PASSWORD=$OS_PASSWORD_INPUT
if value.startswith('$'):
continue
# now match against wanted variable names
if name == 'USERNAME':
self.rc_username = value
elif name == 'AUTH_URL':
self.rc_auth_url = value
elif name == 'TENANT_NAME':
self.rc_tenant_name = value
else:
print 'Error: rc file does not exist %s' % (openrc_file)
success = False
elif not no_env:
# no openrc file passed - we assume the variables have been
# sourced by the calling shell
# just check that they are present
for varname in ['OS_USERNAME', 'OS_AUTH_URL', 'OS_TENANT_NAME']:
if varname not in os.environ:
print 'Warning: %s is missing' % (varname)
success = False
if success:
self.rc_username = os.environ['OS_USERNAME']
self.rc_auth_url = os.environ['OS_AUTH_URL']
self.rc_tenant_name = os.environ['OS_TENANT_NAME']
# always override with CLI argument if provided
if pwd:
self.rc_password = pwd
# if password not know, check from env variable
elif self.rc_auth_url and not self.rc_password and success:
if 'OS_PASSWORD' in os.environ and not no_env:
self.rc_password = os.environ['OS_PASSWORD']
else:
# interactively ask for password
self.rc_password = getpass.getpass(
'Please enter your OpenStack Password: ')
if not self.rc_password:
self.rc_password = ""

120
scale/kloudbuster.py Normal file
View File

@ -0,0 +1,120 @@
# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import argparse
import credentials
import configure
from keystoneclient.v2_0 import client as keystoneclient
import tenant
class KloudBuster(object):
"""
Creates resources on the cloud for loading up the cloud
1. Tenants
2. Users per tenant
3. Routers per user
4. Networks per router
5. Instances per network
"""
def __init__(self):
# List of tenant objects to keep track of all tenants
self.tenant_list = []
self.tenant = None
def runner(self):
"""
The runner for KloudBuster Tests
Executes tests serially
Support concurrency in fututure
"""
# Create the keystone client for tenant and user creation operations
creds = cred.get_credentials()
keystone = keystoneclient.Client(**creds)
# Store the auth url. Pass this around since
# this does not change for all tenants and users
auth_url = creds['auth_url']
# The main tenant creation loop which invokes user creations
# Create tenant resources and trigger User resource creations
for tenant_count in xrange(config_scale.number_tenants):
# For now have a serial naming convention for tenants
tenant_name = "kloudbuster_tenant_" + str(tenant_count)
# Create the tenant and append it to global list
print "Creating tenant %s" % (tenant_name)
self.tenant = tenant.Tenant(tenant_name, keystone, auth_url)
self.tenant_list.append(self.tenant)
# Create the resources associated with the user
# the tenant class creates the user and offloads
# all resource creation inside a user to user class
self.tenant.create_user_elements(config_scale)
# Clean up all resources by default unless specified otherwise
if config_scale.cleanup_resources:
self.teardown_resources()
def teardown_resources(self):
"""
Responsible for cleanup
of all resources
"""
# Clean up all tenant resources
# Tenant class leverages the user class to clean up
# all user resources similar to the create resource flow
for tenant_current in self.tenant_list:
print "Deleting tenant resources for tenant %s" % (tenant_current)
tenant_current.delete_tenant_with_users()
if __name__ == '__main__':
# The default configuration file for CloudScale
default_cfg_file = "cfg.scale.yaml"
# Read the command line arguments and parse them
parser = argparse.ArgumentParser(description="Openstack Scale Test Tool")
parser.add_argument('-r', '--rc', dest='rc',
action='store',
help='source OpenStack credentials from rc file',
metavar='<openrc_file>')
parser.add_argument('-p', '--password', dest='pwd',
action='store',
help='OpenStack password',
metavar='<password>')
parser.add_argument('-d', '--debug', dest='debug',
default=False,
action='store_true',
help='debug flag (very verbose)')
parser.add_argument('--no-env', dest='no_env',
default=False,
action='store_true',
help='do not read env variables')
(opts, args) = parser.parse_known_args()
# Read the configuration file
config_scale = configure.Configuration.from_file(default_cfg_file).configure()
config_scale.debug = opts.debug
# Now parse the openrc file and store credentials
cred = credentials.Credentials(opts.rc, opts.pwd, opts.no_env)
# The KloudBuster class is just a wrapper class
# levarages tenant and user class for resource creations and
# deletion
kloud_buster = KloudBuster()
kloud_buster.runner()

72
scale/tenant.py Normal file
View File

@ -0,0 +1,72 @@
# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import users
class Tenant(object):
"""
Holds the tenant resources
1. Provides ability to create users in a tenant
2. Uses the User class to perform all user resource creation and deletion
"""
def __init__(self, tenant_name, keystone_client, auth_url):
"""
Holds the tenant name
tenant id and keystone client
Also stores the auth_url for constructing credentials
"""
self.tenant_name = tenant_name
self.keystone_client = keystone_client
self.tenant_object = self.keystone_client.tenants.create(tenant_name=tenant_name,
description="Test tenant",
enabled=True)
self.tenant_id = self.tenant_object.id
# Contains a list of user instance objects
self.tenant_user_list = []
self.auth_url = auth_url
def create_user_elements(self, config_scale):
"""
Creates all the entities associated with
a user offloads tasks to user class
"""
# Loop over the required number of users and create resources
for user_count in xrange(config_scale.users_per_tenant):
user_name = "kloudbuster_user_" + self.tenant_name + "_" + str(user_count)
print "Creating user %s" % (user_name)
user_instance = users.User(user_name, config_scale.keystone_admin_role,
self.tenant_id, self.tenant_name,
self.keystone_client,
self.auth_url)
# Global list with all user instances
self.tenant_user_list.append(user_instance)
# Now create the user resources like routers which inturn trigger network and
# vm creation
user_instance.create_user_resources(config_scale)
def delete_tenant_with_users(self):
"""
Delete all user resources and than
deletes the tenant
"""
# Delete all the users in the tenant along with network and compute elements
for user in self.tenant_user_list:
user.delete_user()
# Delete the tenant
self.keystone_client.tenants.delete(self.tenant_id)

108
scale/users.py Normal file
View File

@ -0,0 +1,108 @@
# Copyright 2015 Cisco Systems, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import base_network
from neutronclient.v2_0 import client as neutronclient
from novaclient.client import Client
class User(object):
"""
User class that stores router list
Creates and deletes N routers based on num of routers
"""
def __init__(self, user_name, user_role, tenant_id, tenant_name, keystone_client,
auth_url):
"""
Store all resources
1. Keystone client object
2. Tenant and User information
3. nova and neutron clients
4. router list
"""
self.user_name = user_name
self.keystone_client = keystone_client
self.tenant_id = tenant_id
self.tenant_name = tenant_name
self.user_id = None
self.router_list = []
self.auth_url = auth_url
# Store the neutron and nova client
self.neutron = None
self.nova = None
# Create the user within the given tenant associate
# admin role with user. We need admin role for user
# since we perform VM placement in future
admin_user = self.keystone_client.users.create(name=user_name,
password=user_name,
email="test.com",
tenant_id=tenant_id)
current_role = None
for role in self.keystone_client.roles.list():
if role.name == user_role:
current_role = role
break
self.keystone_client.roles.add_user_role(admin_user, current_role, tenant_id)
self.user_id = admin_user.id
def delete_user(self):
print "Deleting all user resources for user %s" % (self.user_name)
# Delete all user routers
for router in self.router_list:
router.delete_router()
# Finally delete the user
self.keystone_client.users.delete(self.user_id)
def create_user_resources(self, config_scale):
"""
Creates all the User elements associated with a User
1. Creates the routers
2. Creates the neutron and nova client objects
"""
# Create a new neutron client for this User with correct credentials
creden = {}
creden['username'] = self.user_name
creden['password'] = self.user_name
creden['auth_url'] = self.auth_url
creden['tenant_name'] = self.tenant_name
# Create the neutron client to be used for all operations
self.neutron = neutronclient.Client(**creden)
# Create a new nova client for this User with correct credentials
creden_nova = {}
creden_nova['username'] = self.user_name
creden_nova['api_key'] = self.user_name
creden_nova['auth_url'] = self.auth_url
creden_nova['project_id'] = self.tenant_name
creden_nova['version'] = 2
self.nova = Client(**creden_nova)
# Find the external network that routers need to attach to
external_network = base_network.find_external_network(self.neutron)
# Create the required number of routers and append them to router list
print "Creating routers for user %s" % (self.user_name)
for router_count in range(config_scale.routers_per_user):
router_instance = base_network.Router(self.neutron, self.nova, self.user_name)
self.router_list.append(router_instance)
router_name = "kloudbuster_router_" + "_" + str(router_count)
# Create the router and also attach it to external network
router_instance.create_router(router_name, external_network)
# Now create the network resources inside the router
router_instance.create_network_resources(config_scale)