Single/Multinode VPNaaS Scenario Tests using Rally
(a) Refactored the code to work with the following cases 1. Single node with DVR 2. Single node without DVR 3. Multinode with DVR 4. Multinode without DVR |-------------|-------------------------------------------------------| | | Single Node/ Multinode Tests | | Scenarios |-------------------------------------------------------| | | DVR | DVR+Concurrency | Non DVR | Non DVR+Concurrency | |-------------|-----|-----------------|---------|---------------------| | Vpn Basic | x | x | x | x | | Multi Tenant| x | x | x | x | | Vpn Status | x | x | x | x | |-------------|-----|-----------------|---------|---------------------| (b) Used the paramiko package to execute commands over ssh. (c) Moved the README to devref Depends-On: Id3f199d688d648f4618a6850d094e26ca6bb9a7f Change-Id: I24d5a8435f06014fa9164bef518cac62bbb70ef9
This commit is contained in:
parent
e6f643f2a1
commit
22205d681e
@ -34,7 +34,6 @@ VPNaaS Flavors
|
||||
Info on the different Swan flavors, how they are different, and what
|
||||
Operating Systems support them.
|
||||
|
||||
|
||||
VPNaaS Internals
|
||||
-----------------
|
||||
.. toctree::
|
||||
@ -42,6 +41,13 @@ VPNaaS Internals
|
||||
|
||||
multiple-local-subnets
|
||||
|
||||
VPNaaS Rally Tests
|
||||
--------------------
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
vpnaas-rally-test
|
||||
|
||||
Testing
|
||||
-------
|
||||
.. toctree::
|
||||
@ -54,7 +60,6 @@ Testing
|
||||
Add notes about functional testing, with info on how
|
||||
different reference drivers are tested.
|
||||
|
||||
|
||||
Module Reference
|
||||
----------------
|
||||
.. toctree::
|
||||
|
67
doc/source/devref/vpnaas-rally-test.rst
Normal file
67
doc/source/devref/vpnaas-rally-test.rst
Normal file
@ -0,0 +1,67 @@
|
||||
===================
|
||||
VPNaaS Rally Tests
|
||||
===================
|
||||
|
||||
This contains the rally test codes for the Neutron VPN as a Service (VPNaaS) service. The tests
|
||||
currently require rally to be installed via devstack or standalone. It is assumed that you
|
||||
also have Neutron with the Neutron VPNaaS service installed.
|
||||
|
||||
These tests could also be run against a multinode openstack.
|
||||
|
||||
Please see /neutron-vpnaas/devstack/README.md for the required devstack configuration settings
|
||||
for Neutron-VPNaaS.
|
||||
|
||||
Structure:
|
||||
==========
|
||||
|
||||
1. plugins - Directory where you can add rally plugins. Almost everything in Rally is a plugin.
|
||||
Contains base, common methods and actual scenario tests
|
||||
2. rally-configs - Contains input configurations for the scenario tests
|
||||
|
||||
How to test:
|
||||
============
|
||||
|
||||
Included in the repo are rally tests. For information on rally, please see the rally README :
|
||||
|
||||
https://github.com/openstack/rally/blob/master/README.rst
|
||||
|
||||
* Create a rally deployment for your cloud and make sure it is active.
|
||||
rally deployment create --file=cloud_cred.json --name=MyCloud
|
||||
You can also create a rally deployment from the environment variables.
|
||||
rally deployment create --fromenv --name=MyCloud
|
||||
* Create a folder structure as below
|
||||
sudo mkdir /opt/rally
|
||||
* Create a symbolic link to the plugins directory
|
||||
cd /opt/rally
|
||||
sudo ln -s /opt/stack/neutron-vpnaas/rally-jobs/plugins
|
||||
* Run the tests. You can run the tests in various combinations.
|
||||
(a) Single Node with DVR with admin credentials
|
||||
(b) Single Node with DVR with non admin credentials
|
||||
(c) Multi Node with DVR with admin credentials
|
||||
(d) Multi Node with DVR with non admin credentials
|
||||
(e) Single Node, Non DVR with admin credentials
|
||||
(f) Multi Node, Non DVR with admin credentials
|
||||
|
||||
-> Create a args.json file with the correct credentials depending on whether it is a
|
||||
single node or multinode cloud. A args_template.json file is available at
|
||||
/opt/stack/neutron-vpnaas/rally-jobs/rally-configs/args_template.json for your reference.
|
||||
-> Update the rally_config_dvr.yaml or rally_config_non_dvr.yaml file to change the
|
||||
admin/non_admin credentials.
|
||||
-> Use the appropriate config files to run either dvr or non_dvr tests.
|
||||
|
||||
With DVR:
|
||||
rally task start /opt/stack/neutron-vpnaas/rally-jobs/rally-configs/rally_config_dvr.yaml
|
||||
--task-args-file /opt/stack/neutron-vpnaas/rally-jobs/rally-configs/args.json
|
||||
|
||||
Non DVR:
|
||||
rally task start /opt/stack/neutron-vpnaas/rally-jobs/rally-configs/rally_config_non_dvr.yaml
|
||||
--task-args-file /opt/stack/neutron-vpnaas/rally-jobs/rally-configs/args.json
|
||||
|
||||
**Note:**
|
||||
Non DVR scenario can only be run as admin as you need admin credentials to create
|
||||
a non DVR router.
|
||||
|
||||
External Resources:
|
||||
===================
|
||||
|
||||
For more information on the rally testing framework see: <https://github.com/openstack/rally>
|
@ -1,36 +0,0 @@
|
||||
Welcome!
|
||||
========
|
||||
|
||||
This contains rally testing code for the Neutron VPN as a Service (VPNaaS) service. The tests
|
||||
currently require rally to be installed via devstack or standalone. It is assumed that you
|
||||
also have Neutron with the Neutron VPNaaS service installed.
|
||||
|
||||
Please see /neutron-vpnaas/devstack/README.md for the required devstack configuration settings
|
||||
for Neutron-VPNaaS.
|
||||
|
||||
Structure:
|
||||
==========
|
||||
|
||||
1. plugins - Directory where you can add rally plugins. Almost everything in Rally is a plugin.
|
||||
Contains base, common methods and actual scenario tests
|
||||
2. rally-configs - Contains input config for the scenario tests
|
||||
|
||||
How to test:
|
||||
============
|
||||
|
||||
Included in the repo are rally tests. For information on rally, please see the rally README :
|
||||
|
||||
https://github.com/openstack/rally/blob/master/README.rst
|
||||
|
||||
* Create the folder structure as below
|
||||
$> sudo mkdir /opt/rally
|
||||
* Create a symbolic link to the plugin
|
||||
$> cd /opt/rally
|
||||
$> sudo ln -s /opt/stack/neutron-vpnaas/rally-jobs/plugins
|
||||
* Run the tests
|
||||
$> rally task start /opt/stack/neutron-vpnaas/rally-jobs/rally-configs/rally_config.yaml
|
||||
|
||||
External Resources:
|
||||
===================
|
||||
|
||||
For more information on the rally testing framework see: <https://github.com/openstack/rally>
|
@ -14,22 +14,20 @@
|
||||
|
||||
from neutron_vpnaas._i18n import _LI
|
||||
from rally.common import log as logging
|
||||
|
||||
from rally.task import scenario
|
||||
from rally.task import types as types
|
||||
import vpn_base
|
||||
|
||||
import vpn_base
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VpnBasicScenario(vpn_base.VpnBase):
|
||||
class TestVpnBasicScenario(vpn_base.VpnBase):
|
||||
"""Rally scenarios for VPNaaS"""
|
||||
|
||||
@types.set(image=types.ImageResourceType,
|
||||
flavor=types.FlavorResourceType)
|
||||
@scenario.configure()
|
||||
def create_and_delete_vpn_connection(
|
||||
self, **kwargs):
|
||||
def create_and_delete_vpn_connection(self, **kwargs):
|
||||
"""Basic VPN connectivity scenario.
|
||||
|
||||
1. Create 2 private networks, subnets and routers
|
||||
@ -44,10 +42,10 @@ class VpnBasicScenario(vpn_base.VpnBase):
|
||||
8. Create VPN service at each of the routers
|
||||
9. Create IPSEC site connections at both endpoints
|
||||
10. Verify that the ipsec-site-connection is ACTIVE (takes upto 30secs)
|
||||
11. To verify the vpn connectivity, get into the first snat
|
||||
11. To verify the vpn connectivity, get into the peer router's snat
|
||||
namespace and start a tcpdump at the qg-xxxx interface
|
||||
12. SSH into the second instance from the second qrouter namespace
|
||||
and try to ping the first instance
|
||||
12. SSH into the nova instance from the local qrouter namespace
|
||||
and try to ping the nova instance on the peer network.
|
||||
14. Verify that the captured packets are encapsulated and encrypted.
|
||||
15. Verify the connectivity in the reverse direction following the
|
||||
steps 11 through 13
|
||||
@ -55,16 +53,17 @@ class VpnBasicScenario(vpn_base.VpnBase):
|
||||
"""
|
||||
|
||||
try:
|
||||
self.setup()
|
||||
self.create_networks_and_servers(**kwargs)
|
||||
self.setup(**kwargs)
|
||||
self.create_networks(**kwargs)
|
||||
self.create_servers(**kwargs)
|
||||
self.check_route()
|
||||
self.ike_policy = self._create_ike_policy(**kwargs)
|
||||
self.ipsec_policy = self._create_ipsec_policy(**kwargs)
|
||||
self.create_vpn_services()
|
||||
self.create_ipsec_site_connections(**kwargs)
|
||||
self.assert_statuses(final_status='ACTIVE', **kwargs)
|
||||
self.assert_vpn_connectivity()
|
||||
LOG.info(_LI("VPN CONNECTIVITY TEST PASSED!!"))
|
||||
self.verify_vpn_connectivity(**kwargs)
|
||||
LOG.info(_LI("VPN CONNECTIVITY TEST PASSED!"))
|
||||
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
@ -12,17 +12,21 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron_vpnaas._i18n import _LI
|
||||
from rally.common import log as logging
|
||||
from rally.task import scenario
|
||||
from rally.task import types as types
|
||||
|
||||
import vpn_base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
class TestVPNStatusScenario(vpn_base.VpnBase):
|
||||
|
||||
class TestVpnStatusScenario(vpn_base.VpnBase):
|
||||
@types.set(image=types.ImageResourceType,
|
||||
flavor=types.FlavorResourceType)
|
||||
@scenario.configure()
|
||||
def check_vpn_status(
|
||||
self, **kwargs):
|
||||
def check_vpn_status(self, **kwargs):
|
||||
"""Test VPN's status correctly after bringing router's status to
|
||||
DOWN and back to ACTIVE state
|
||||
|
||||
@ -45,8 +49,8 @@ class TestVPNStatusScenario(vpn_base.VpnBase):
|
||||
"""
|
||||
|
||||
try:
|
||||
self.setup()
|
||||
self.create_networks_and_servers(**kwargs)
|
||||
self.setup(**kwargs)
|
||||
self.create_networks(**kwargs)
|
||||
self.check_route()
|
||||
self.ike_policy = self._create_ike_policy(**kwargs)
|
||||
self.ipsec_policy = self._create_ipsec_policy(**kwargs)
|
||||
@ -59,6 +63,7 @@ class TestVPNStatusScenario(vpn_base.VpnBase):
|
||||
self.update_router(self.router_ids[0], admin_state_up=True)
|
||||
self.update_router(self.router_ids[1], admin_state_up=True)
|
||||
self.assert_statuses(final_status='ACTIVE', **kwargs)
|
||||
LOG.info(_LI("VPN STATUS TEST PASSED!"))
|
||||
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
@ -12,21 +12,24 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron_vpnaas._i18n import _LI
|
||||
from rally.common import log as logging
|
||||
from rally.task import scenario
|
||||
from rally.task import types as types
|
||||
|
||||
import vpn_base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
class VpnTenantScenario(vpn_base.VpnBase):
|
||||
|
||||
class TestVpnTenantScenario(vpn_base.VpnBase):
|
||||
"""Rally scenarios for VPNaaS"""
|
||||
|
||||
@types.set(image=types.ImageResourceType,
|
||||
flavor=types.FlavorResourceType)
|
||||
@scenario.configure()
|
||||
def multitenants_vpn_test(
|
||||
self, **kwargs):
|
||||
"""Basic VPN connectivity scenario.
|
||||
def multitenants_vpn_test(self, **kwargs):
|
||||
"""Test VPN connectivity under two different tenants.
|
||||
|
||||
1. Create 2 private networks with 2 different tenants, subnets, routers
|
||||
2. Create public network, subnets and GW IPs on routers, if not present
|
||||
@ -41,19 +44,19 @@ class VpnTenantScenario(vpn_base.VpnBase):
|
||||
9. Create IPSEC site connections at both endpoints
|
||||
10. Verify that the vpn-service and ipsec-site-connection are ACTIVE
|
||||
11. Cleanup the resources that are setup for this test
|
||||
|
||||
"""
|
||||
|
||||
try:
|
||||
self.setup(use_admin_client=True)
|
||||
self.create_tenant()
|
||||
self.create_networks_and_servers(**kwargs)
|
||||
self.setup(**kwargs)
|
||||
self.create_tenants()
|
||||
self.create_networks(**kwargs)
|
||||
self.check_route()
|
||||
self.ike_policy = self._create_ike_policy(**kwargs)
|
||||
self.ipsec_policy = self._create_ipsec_policy(**kwargs)
|
||||
self.create_vpn_services()
|
||||
self.create_ipsec_site_connections(**kwargs)
|
||||
self.assert_statuses(final_status='ACTIVE', **kwargs)
|
||||
LOG.info(_LI("VPN TENANT TEST PASSED!"))
|
||||
|
||||
finally:
|
||||
self.cleanup()
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
import concurrent.futures
|
||||
import exceptions
|
||||
import multiprocessing
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
@ -26,68 +26,155 @@ from rally.task import atomic
|
||||
import vpn_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
LOCK = multiprocessing.RLock()
|
||||
LOCK = threading.RLock()
|
||||
MAX_RESOURCES = 2
|
||||
|
||||
|
||||
class VpnBase(rally_base.OpenStackScenario):
|
||||
|
||||
def setup(self, use_admin_client=False):
|
||||
"""Creates and initializes data structures to hold various resources
|
||||
:param use_admin_client: Use admin client when it is set to True
|
||||
"""
|
||||
self.tenant_ids = []
|
||||
self.snat_namespaces = []
|
||||
self.qrouter_namespaces = []
|
||||
self.router_ids = []
|
||||
self.rally_router_gw_ips = []
|
||||
self.rally_routers = []
|
||||
self.rally_networks = []
|
||||
self.rally_subnets = []
|
||||
self.rally_cidrs = []
|
||||
self.ike_policy = None
|
||||
self.ipsec_policy = None
|
||||
self.vpn_services = []
|
||||
self.ipsec_site_connections = []
|
||||
self.servers = []
|
||||
self.server_private_ips = []
|
||||
self.suffixes = [uuidutils.generate_uuid(), uuidutils.generate_uuid()]
|
||||
self.tenant_names = map(lambda x: "rally_tenant_" + x, self.suffixes)
|
||||
self.key_names = map(lambda x: "rally_keypair_" + x, self.suffixes)
|
||||
self.key_file_paths = map(lambda x: '/tmp/' + x, self.key_names)
|
||||
self.nova_client = self.clients("nova")
|
||||
self.neutron_client = self.clients("neutron")
|
||||
self.neutron_admin_client = self.admin_clients("neutron")
|
||||
if use_admin_client is True:
|
||||
self.neutron_client = self.admin_clients("neutron")
|
||||
self.keystone_client = self.admin_clients("keystone")
|
||||
self.nova_client = self.admin_clients("nova")
|
||||
def setup(self, **kwargs):
|
||||
"""Create and initialize data structures to hold various resources"""
|
||||
|
||||
@atomic.action_timer("cleanup")
|
||||
def cleanup(self):
|
||||
"""Cleans up all the resources"""
|
||||
with LOCK:
|
||||
LOG.debug('SETUP RESOURCES')
|
||||
self.neutron_admin_client = self.admin_clients("neutron")
|
||||
if kwargs['use_admin_client']:
|
||||
self.neutron_client = self.neutron_admin_client
|
||||
self.keystone_client = self.admin_clients("keystone")
|
||||
self.nova_client = self.admin_clients("nova")
|
||||
else:
|
||||
self.neutron_client = self.clients("neutron")
|
||||
self.nova_client = self.clients("nova")
|
||||
self.suffixes = [uuidutils.generate_uuid(),
|
||||
uuidutils.generate_uuid()]
|
||||
self.remote_key_files = ['rally_keypair_' + x
|
||||
for x in self.suffixes]
|
||||
self.local_key_files = ['/tmp/' + x for x in self.remote_key_files]
|
||||
self.private_key_file = kwargs["private_key"]
|
||||
self.keypairs = []
|
||||
self.tenant_ids = []
|
||||
self.ns_controller_tuples = []
|
||||
self.qrouterns_compute_tuples = []
|
||||
self.router_ids = []
|
||||
self.rally_router_gw_ips = []
|
||||
self.rally_routers = []
|
||||
self.rally_networks = []
|
||||
self.rally_subnets = []
|
||||
self.rally_cidrs = []
|
||||
self.ike_policy = None
|
||||
self.ipsec_policy = None
|
||||
self.vpn_services = []
|
||||
self.ipsec_site_connections = []
|
||||
self.servers = []
|
||||
self.server_private_ips = []
|
||||
self.server_fips = []
|
||||
|
||||
vpn_utils.delete_servers(self.nova_client, self.servers)
|
||||
vpn_utils.delete_hosts_from_knownhosts_file(self.server_private_ips)
|
||||
vpn_utils.delete_key_files(self.key_file_paths)
|
||||
self._delete_ipsec_site_connections()
|
||||
self._delete_vpn_services()
|
||||
self._delete_ipsec_policy()
|
||||
self._delete_ike_policy()
|
||||
vpn_utils.delete_network(
|
||||
self.neutron_client, self.neutron_admin_client, self.rally_routers,
|
||||
self.rally_networks, self.rally_subnets)
|
||||
if self.tenant_ids:
|
||||
vpn_utils.delete_tenant(self.keystone_client,
|
||||
self.tenant_ids)
|
||||
def create_tenants(self):
|
||||
"""Create tenants"""
|
||||
|
||||
for x in range(MAX_RESOURCES):
|
||||
tenant_id = vpn_utils.create_tenant(
|
||||
self.keystone_client, self.suffixes[x])
|
||||
with LOCK:
|
||||
self.tenant_ids.append(tenant_id)
|
||||
|
||||
def create_networks(self, **kwargs):
|
||||
"""Create networks to test vpn connectivity"""
|
||||
|
||||
for x in range(MAX_RESOURCES):
|
||||
if self.tenant_ids:
|
||||
router, network, subnet, cidr = vpn_utils.create_network(
|
||||
self.neutron_client, self.neutron_admin_client,
|
||||
self.suffixes[x], tenant_id=self.tenant_ids[x],
|
||||
DVR_flag=kwargs["DVR_flag"],
|
||||
ext_net_name=kwargs["ext-net"])
|
||||
else:
|
||||
router, network, subnet, cidr = vpn_utils.create_network(
|
||||
self.neutron_client, self.neutron_admin_client,
|
||||
self.suffixes[x], DVR_flag=kwargs["DVR_flag"],
|
||||
ext_net_name=kwargs["ext-net"])
|
||||
with LOCK:
|
||||
self.rally_cidrs.append(cidr)
|
||||
self.rally_subnets.append(subnet)
|
||||
self.rally_networks.append(network)
|
||||
self.rally_routers.append(router)
|
||||
self.router_ids.append(router["router"]['id'])
|
||||
self.rally_router_gw_ips.append(
|
||||
router["router"]["external_gateway_info"]
|
||||
["external_fixed_ips"][0]["ip_address"])
|
||||
|
||||
if(kwargs["DVR_flag"]):
|
||||
ns, controller = vpn_utils.wait_for_namespace_creation(
|
||||
"snat-", router["router"]['id'],
|
||||
kwargs['controller_creds'],
|
||||
self.private_key_file,
|
||||
kwargs['namespace_creation_timeout'])
|
||||
else:
|
||||
ns, controller = vpn_utils.wait_for_namespace_creation(
|
||||
"qrouter-", router["router"]['id'],
|
||||
kwargs['controller_creds'],
|
||||
self.private_key_file,
|
||||
kwargs['namespace_creation_timeout'])
|
||||
with LOCK:
|
||||
self.ns_controller_tuples.append((ns, controller))
|
||||
|
||||
def create_servers(self, **kwargs):
|
||||
"""Create servers"""
|
||||
|
||||
for x in range(MAX_RESOURCES):
|
||||
kwargs.update({
|
||||
"nics":
|
||||
[{"net-id": self.rally_networks[x]["network"]["id"]}],
|
||||
"sec_group_suffix": self.suffixes[x],
|
||||
"server_suffix": self.suffixes[x]
|
||||
})
|
||||
keypair = vpn_utils.create_keypair(
|
||||
self.nova_client, self.suffixes[x])
|
||||
server = vpn_utils.create_server(
|
||||
self.nova_client, keypair, **kwargs)
|
||||
vpn_utils.assert_server_status(server, **kwargs)
|
||||
with LOCK:
|
||||
self.servers.append(server)
|
||||
self.keypairs.append(keypair)
|
||||
self.server_private_ips.append(vpn_utils.get_server_ip(
|
||||
self.nova_client, server.id, self.suffixes[x]))
|
||||
if(kwargs["DVR_flag"]):
|
||||
qrouter, compute = vpn_utils.wait_for_namespace_creation(
|
||||
"qrouter-", self.router_ids[x],
|
||||
kwargs['compute_creds'],
|
||||
self.private_key_file,
|
||||
kwargs['namespace_creation_timeout'])
|
||||
|
||||
vpn_utils.write_key_to_compute_node(
|
||||
keypair, self.local_key_files[x],
|
||||
self.remote_key_files[x], compute,
|
||||
self.private_key_file)
|
||||
with LOCK:
|
||||
self.qrouterns_compute_tuples.append((qrouter, compute))
|
||||
else:
|
||||
vpn_utils.write_key_to_local_path(self.keypairs[x],
|
||||
self.local_key_files[x])
|
||||
fip = vpn_utils.add_floating_ip(self.nova_client, server)
|
||||
with LOCK:
|
||||
self.server_fips.append(fip)
|
||||
|
||||
def check_route(self):
|
||||
"""Verify route exists between the router gateways"""
|
||||
|
||||
LOG.debug("VERIFY ROUTE EXISTS BETWEEN THE ROUTER GATEWAYS")
|
||||
for tuple in self.ns_controller_tuples:
|
||||
for ip in self.rally_router_gw_ips:
|
||||
assert(vpn_utils.ping_router_gateway(
|
||||
tuple, ip, self.private_key_file)), (
|
||||
"PING TO IP " + ip + " FAILED")
|
||||
|
||||
@atomic.action_timer("_create_ike_policy")
|
||||
def _create_ike_policy(self, **kwargs):
|
||||
"""Creates IKE policy
|
||||
"""Create IKE policy
|
||||
|
||||
:return: IKE policy
|
||||
"""
|
||||
LOG.debug("CREATING IKE_POLICY")
|
||||
LOG.debug('CREATING IKE_POLICY')
|
||||
ike_policy = self.neutron_client.create_ikepolicy({
|
||||
"ikepolicy": {
|
||||
"phase1_negotiation_mode":
|
||||
@ -107,11 +194,11 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
|
||||
@atomic.action_timer("_create_ipsec_policy")
|
||||
def _create_ipsec_policy(self, **kwargs):
|
||||
"""Creates IPSEC policy
|
||||
"""Create IPSEC policy
|
||||
|
||||
:return: IPSEC policy
|
||||
"""
|
||||
LOG.debug("CREATING IPSEC_POLICY")
|
||||
LOG.debug('CREATING IPSEC_POLICY')
|
||||
ipsec_policy = self.neutron_client.create_ipsecpolicy({
|
||||
"ipsecpolicy": {
|
||||
"name": "rally_ipsecpolicy",
|
||||
@ -131,16 +218,15 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
return ipsec_policy
|
||||
|
||||
@atomic.action_timer("_create_vpn_service")
|
||||
def _create_vpn_service(self, rally_subnet,
|
||||
rally_router, vpn_suffix=None):
|
||||
"""Creates VPN service endpoints
|
||||
def _create_vpn_service(self, rally_subnet, rally_router, vpn_suffix=None):
|
||||
"""Create VPN service endpoints
|
||||
|
||||
:param rally_subnet: local subnet
|
||||
:param rally_router: router endpoint
|
||||
:param vpn_suffix: suffix name for vpn service
|
||||
:return: VPN service
|
||||
"""
|
||||
LOG.debug("CREATING VPN_SERVICE")
|
||||
LOG.debug('CREATING VPN_SERVICE')
|
||||
vpn_service = self.neutron_client.create_vpnservice({
|
||||
"vpnservice": {
|
||||
"subnet_id": rally_subnet["subnet"]["id"],
|
||||
@ -151,16 +237,24 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
})
|
||||
return vpn_service
|
||||
|
||||
def create_vpn_services(self):
|
||||
"""Create VPN services"""
|
||||
|
||||
for x in range(MAX_RESOURCES):
|
||||
vpn_service = self._create_vpn_service(
|
||||
self.rally_subnets[x], self.rally_routers[x], self.suffixes[x])
|
||||
with LOCK:
|
||||
self.vpn_services.append(vpn_service)
|
||||
|
||||
@atomic.action_timer("_create_ipsec_site_connection")
|
||||
def _create_ipsec_site_connection(self, local_index,
|
||||
peer_index, **kwargs):
|
||||
"""Creates IPSEC site connection
|
||||
def _create_ipsec_site_connection(self, local_index, peer_index, **kwargs):
|
||||
"""Create IPSEC site connection
|
||||
|
||||
:param local_index: parameter to point to the local end-point
|
||||
:param peer_index: parameter to point to the peer end-point
|
||||
:return: IPSEC site connection
|
||||
"""
|
||||
LOG.debug("CREATING IPSEC_SITE_CONNECTION")
|
||||
LOG.debug('CREATING IPSEC_SITE_CONNECTION')
|
||||
ipsec_site_conn = self.neutron_client.create_ipsec_site_connection({
|
||||
"ipsec_site_connection": {
|
||||
"psk": kwargs.get("secret", "secret"),
|
||||
@ -185,26 +279,31 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
})
|
||||
return ipsec_site_conn
|
||||
|
||||
def create_ipsec_site_connections(self, **kwargs):
|
||||
"""Create IPSEC site connections"""
|
||||
|
||||
a = self._create_ipsec_site_connection(0, 1, **kwargs)
|
||||
b = self._create_ipsec_site_connection(1, 0, **kwargs)
|
||||
with LOCK:
|
||||
self.ipsec_site_connections = [a, b]
|
||||
|
||||
def _get_resource(self, resource_tag, resource_id):
|
||||
"""Gets the resource(vpn_service or ipsec_site_connection)
|
||||
"""Get the resource(vpn_service or ipsec_site_connection)
|
||||
|
||||
:param resource_tag: "vpnservice" or "ipsec_site_connection"
|
||||
:param resource_id: id of the resource
|
||||
:return: resource (vpn_service or ipsec_site_connection)
|
||||
"""
|
||||
if resource_tag == "vpnservice":
|
||||
vpn_service = self.neutron_client.show_vpnservice(
|
||||
resource_id)
|
||||
vpn_service = self.neutron_client.show_vpnservice(resource_id)
|
||||
if vpn_service:
|
||||
return vpn_service
|
||||
elif resource_tag == 'ipsec_site_connection':
|
||||
ipsec_site_conn = \
|
||||
self.neutron_client.show_ipsec_site_connection(
|
||||
resource_id)
|
||||
ipsec_site_conn = self.neutron_client.show_ipsec_site_connection(
|
||||
resource_id)
|
||||
if ipsec_site_conn:
|
||||
return ipsec_site_conn
|
||||
|
||||
@atomic.action_timer("_wait_for_status_change")
|
||||
def _wait_for_status_change(self, resource, resource_tag, final_status,
|
||||
wait_timeout=60, check_interval=1):
|
||||
"""Wait for resource's status change
|
||||
@ -214,16 +313,18 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
:param resource: resource whose status has to be checked
|
||||
:param final_status: desired final status of the resource
|
||||
:param resource_tag: to identify the resource as vpnservice or
|
||||
ipsec_site_connection
|
||||
ipsec_site_connection
|
||||
:param wait_timeout: timeout value in seconds
|
||||
:param check_interval: time to sleep before each check for the status
|
||||
change
|
||||
:return: resource
|
||||
"""
|
||||
LOG.debug('WAIT_FOR_%s_STATUS_CHANGE ', resource[resource_tag]['id'])
|
||||
|
||||
start_time = time.time()
|
||||
while True:
|
||||
resource = self._get_resource(resource_tag,
|
||||
resource[resource_tag]['id'])
|
||||
resource = self._get_resource(
|
||||
resource_tag, resource[resource_tag]['id'])
|
||||
current_status = resource[resource_tag]['status']
|
||||
if current_status == final_status:
|
||||
return resource
|
||||
@ -231,9 +332,9 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
if time.time() - start_time > wait_timeout:
|
||||
raise exceptions.Exception(
|
||||
"Timeout waiting for resource {} to change to {} status".
|
||||
format(resource[resource_tag]['name'], final_status)
|
||||
)
|
||||
format(resource[resource_tag]['name'], final_status))
|
||||
|
||||
@atomic.action_timer("wait_time_for_status_change")
|
||||
def _assert_statuses(self, ipsec_site_conn, vpn_service,
|
||||
final_status, **kwargs):
|
||||
"""Assert statuses of vpn_service and ipsec_site_connection
|
||||
@ -258,207 +359,166 @@ class VpnBase(rally_base.OpenStackScenario):
|
||||
check_interval=5)
|
||||
|
||||
LOG.debug("VPN SERVICE STATUS %s", vpn_service['vpnservice']['status'])
|
||||
LOG.debug("IPSEC_SITE_CONNECTION STATUS: %s",
|
||||
LOG.debug("IPSEC_SITE_CONNECTION STATUS %s",
|
||||
ipsec_site_conn['ipsec_site_connection']['status'])
|
||||
|
||||
self._validate_status(vpn_service, ipsec_site_conn, final_status)
|
||||
def assert_statuses(self, final_status, **kwargs):
|
||||
"""Assert active statuses for VPN services and VPN connections
|
||||
|
||||
def _validate_status(self, vpn_service, ipsec_site_conn, final_status):
|
||||
"""Validate the statuses of vpn_service, ipsec_site_connection and
|
||||
evaluate the final_status
|
||||
|
||||
:param ipsec_site_conn: ipsec_site_connection of an instance
|
||||
:param vpn_service: vpn_service of an instance
|
||||
:param final_status: status of vpn and ipsec_site_connection instance
|
||||
:param final_status: the final status you expect the resource to be in
|
||||
"""
|
||||
|
||||
assert(final_status == vpn_service['vpnservice']['status']), (
|
||||
"VPN SERVICE IS NOT IN %s STATE" % final_status)
|
||||
assert(final_status == ipsec_site_conn['ipsec_site_connection']
|
||||
['status']), ("THE IPSEC SITE CONNECTION IS NOT IN %s STATE"
|
||||
% final_status)
|
||||
LOG.debug("ASSERTING ACTIVE STATUSES FOR VPN-SERVICES AND "
|
||||
"IPSEC-SITE-CONNECTIONS")
|
||||
for x in range(MAX_RESOURCES):
|
||||
self._assert_statuses(
|
||||
self.ipsec_site_connections[x], self.vpn_services[x],
|
||||
final_status, **kwargs)
|
||||
|
||||
def _get_qg_interface(self, peer_index):
|
||||
"""Get the qg- interface
|
||||
|
||||
:param peer_index: parameter to point to the local end-point
|
||||
:return: qg-interface
|
||||
"""
|
||||
qg = vpn_utils.get_interfaces(
|
||||
self.ns_controller_tuples[peer_index],
|
||||
self.private_key_file)
|
||||
p = re.compile(r"qg-\w+-\w+")
|
||||
for line in qg:
|
||||
m = p.search(line)
|
||||
if m:
|
||||
return m.group()
|
||||
return None
|
||||
|
||||
@atomic.action_timer("_verify_vpn_connection")
|
||||
def _verify_vpn_connection(self, local_index, peer_index):
|
||||
"""Verifies the vpn connectivity between the endpoints
|
||||
def _verify_vpn_connectivity(self, local_index, peer_index, **kwargs):
|
||||
"""Verify the vpn connectivity between the endpoints
|
||||
|
||||
Get the qg- interface from the snat namespace corresponding to the
|
||||
peer router and start a tcp dump. Concurrently, SSH into the nova
|
||||
instance on the local subnet from the qrouter namespace and try
|
||||
to ping the nova instance on the peer subnet. Inspect the captured
|
||||
packets to see if they are encrypted.
|
||||
:param local_index: parameter to point to the local end-point
|
||||
:param peer_index: parameter to point to the peer end-point
|
||||
:return: True or False
|
||||
:return: True if vpn connectivity test passes
|
||||
False if the test fails
|
||||
"""
|
||||
qg = vpn_utils.get_interfaces(self.snat_namespaces[peer_index])
|
||||
if qg:
|
||||
p = re.compile(r"qg-\w+-\w+")
|
||||
m = p.search(qg)
|
||||
if m:
|
||||
qg_interface = m.group()
|
||||
else:
|
||||
qg_interface = None
|
||||
qg_interface = self._get_qg_interface(peer_index)
|
||||
if qg_interface:
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as e:
|
||||
tcpdump_future = e.submit(vpn_utils.start_tcpdump,
|
||||
self.ns_controller_tuples[peer_index],
|
||||
qg_interface, self.private_key_file)
|
||||
if(kwargs["DVR_flag"]):
|
||||
ssh_future = e.submit(
|
||||
vpn_utils.ssh_and_ping_server,
|
||||
self.server_private_ips[local_index],
|
||||
self.server_private_ips[peer_index],
|
||||
self.qrouterns_compute_tuples[local_index],
|
||||
self.remote_key_files[local_index],
|
||||
self.private_key_file)
|
||||
else:
|
||||
ssh_future = e.submit(
|
||||
vpn_utils.ssh_and_ping_server_with_fip,
|
||||
self.server_fips[local_index],
|
||||
self.server_private_ips[peer_index],
|
||||
self.local_key_files[local_index],
|
||||
self.private_key_file)
|
||||
|
||||
if qg_interface:
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as e:
|
||||
tcpdump_future = e.submit(vpn_utils.start_tcpdump,
|
||||
self.snat_namespaces[peer_index],
|
||||
qg_interface)
|
||||
ssh_future = e.submit(vpn_utils.ssh_and_ping_server,
|
||||
self.server_private_ips[local_index],
|
||||
self.server_private_ips[peer_index],
|
||||
self.qrouter_namespaces[local_index],
|
||||
self.key_file_paths[local_index])
|
||||
assert(ssh_future.result()), "SSH/Ping failed"
|
||||
lines = tcpdump_future.result().split('\n')
|
||||
for line in lines:
|
||||
if 'ESP' in line:
|
||||
return True
|
||||
assert(ssh_future.result()), "SSH/Ping failed"
|
||||
for line in tcpdump_future.result():
|
||||
if 'ESP' in line:
|
||||
return True
|
||||
return False
|
||||
|
||||
def verify_vpn_connectivity(self, **kwargs):
|
||||
"""Verify VPN connectivity"""
|
||||
|
||||
LOG.debug("VERIFY THE VPN CONNECTIVITY")
|
||||
with LOCK:
|
||||
assert(self._verify_vpn_connectivity(
|
||||
0, 1, **kwargs)), "VPN CONNECTION FAILED"
|
||||
with LOCK:
|
||||
assert(self._verify_vpn_connectivity(
|
||||
1, 0, **kwargs)), "VPN CONNECTION FAILED"
|
||||
|
||||
def update_router(self, router_id, admin_state_up=False):
|
||||
"""Update router's admin_state_up field
|
||||
|
||||
:param router_id: uuid of the router
|
||||
:param admin_state_up: True or False
|
||||
"""
|
||||
LOG.debug('UPDATE ROUTER')
|
||||
router_args = {'router': {'admin_state_up': admin_state_up}}
|
||||
self.neutron_client.update_router(router_id, router_args)
|
||||
|
||||
@atomic.action_timer("_delete_ipsec_site_connection")
|
||||
def _delete_ipsec_site_connections(self):
|
||||
"""Deletes IPSEC site connections"""
|
||||
"""Delete IPSEC site connections"""
|
||||
|
||||
if self.ipsec_site_connections:
|
||||
for site_conn in self.ipsec_site_connections:
|
||||
if "rally" in (site_conn['ipsec_site_connection']['name']):
|
||||
LOG.debug("DELETING IPSEC_SITE_CONNECTION %s",
|
||||
site_conn['ipsec_site_connection']['id'])
|
||||
self.neutron_client.delete_ipsec_site_connection(
|
||||
site_conn['ipsec_site_connection']['id'])
|
||||
for site_conn in self.ipsec_site_connections:
|
||||
LOG.debug("DELETING IPSEC_SITE_CONNECTION %s",
|
||||
site_conn['ipsec_site_connection']['id'])
|
||||
self.neutron_client.delete_ipsec_site_connection(
|
||||
site_conn['ipsec_site_connection']['id'])
|
||||
|
||||
@atomic.action_timer("_delete_vpn_service")
|
||||
def _delete_vpn_services(self):
|
||||
"""Deletes VPN service endpoints"""
|
||||
"""Delete VPN service endpoints"""
|
||||
|
||||
if self.vpn_services:
|
||||
for vpn_service in self.vpn_services:
|
||||
if "rally" in vpn_service['vpnservice']['name']:
|
||||
LOG.debug("DELETING VPN_SERVICE %s",
|
||||
vpn_service['vpnservice']['id'])
|
||||
self.neutron_client.delete_vpnservice(
|
||||
vpn_service['vpnservice']['id'])
|
||||
for vpn_service in self.vpn_services:
|
||||
LOG.debug("DELETING VPN_SERVICE %s",
|
||||
vpn_service['vpnservice']['id'])
|
||||
self.neutron_client.delete_vpnservice(
|
||||
vpn_service['vpnservice']['id'])
|
||||
|
||||
@atomic.action_timer("_delete_ipsec_policy")
|
||||
def _delete_ipsec_policy(self):
|
||||
"""Deletes IPSEC policy
|
||||
"""Delete IPSEC policy"""
|
||||
|
||||
:param ipsec_policy: ipsec_policy object
|
||||
:return:
|
||||
"""
|
||||
LOG.debug("DELETING IPSEC POLICY")
|
||||
if (self.ipsec_policy and
|
||||
"rally" in self.ipsec_policy['ipsecpolicy']['name']):
|
||||
if self.ipsec_policy:
|
||||
self.neutron_client.delete_ipsecpolicy(
|
||||
self.ipsec_policy['ipsecpolicy']['id'])
|
||||
|
||||
@atomic.action_timer("_delete_ike_policy")
|
||||
def _delete_ike_policy(self):
|
||||
"""Deletes IKE policy
|
||||
"""Delete IKE policy"""
|
||||
|
||||
:param ike_policy: ike_policy object
|
||||
:return:
|
||||
"""
|
||||
LOG.debug("DELETING IKE POLICY")
|
||||
if (self.ike_policy and
|
||||
"rally" in self.ike_policy['ikepolicy']['name']):
|
||||
LOG.debug('DELETING IKE POLICY')
|
||||
if self.ike_policy:
|
||||
self.neutron_client.delete_ikepolicy(
|
||||
self.ike_policy['ikepolicy']['id'])
|
||||
|
||||
def create_tenant(self):
|
||||
"""Creates tenant
|
||||
@atomic.action_timer("cleanup")
|
||||
def cleanup(self):
|
||||
"""Clean the resources"""
|
||||
|
||||
:param keystone_client: keystone_admin_client
|
||||
:param tenant_ids: append created tenant id into the list
|
||||
:return:
|
||||
"""
|
||||
with LOCK:
|
||||
for x in range(MAX_RESOURCES):
|
||||
self.tenant_ids.append((vpn_utils.create_tenant(
|
||||
self.keystone_client,
|
||||
self.tenant_names[x])).id)
|
||||
vpn_utils.delete_servers(self.nova_client, self.servers)
|
||||
if self.server_fips:
|
||||
vpn_utils.delete_floating_ips(self.nova_client, self.server_fips)
|
||||
vpn_utils.delete_keypairs(self.nova_client, self.keypairs)
|
||||
|
||||
def create_networks_and_servers(self, **kwargs):
|
||||
with LOCK:
|
||||
keypairs = []
|
||||
for x in range(MAX_RESOURCES):
|
||||
if self.tenant_ids:
|
||||
router, network, subnet, cidr = vpn_utils.create_network(
|
||||
self.neutron_client, self.neutron_admin_client,
|
||||
self.suffixes[x], self.tenant_ids[x])
|
||||
else:
|
||||
router, network, subnet, cidr = vpn_utils.create_network(
|
||||
self.neutron_client, self.neutron_admin_client,
|
||||
self.suffixes[x])
|
||||
self.rally_cidrs.append(cidr)
|
||||
self.rally_subnets.append(subnet)
|
||||
self.rally_networks.append(network)
|
||||
self.rally_routers.append(router)
|
||||
self.router_ids.append(router["router"]['id'])
|
||||
self.rally_router_gw_ips.append(
|
||||
router["router"]["external_gateway_info"]
|
||||
["external_fixed_ips"][0]["ip_address"])
|
||||
self.snat_namespaces.append(
|
||||
vpn_utils.wait_for_namespace_creation(
|
||||
"snat-", router, **kwargs))
|
||||
self.qrouter_namespaces.append(
|
||||
vpn_utils.wait_for_namespace_creation(
|
||||
"qrouter-", router, **kwargs))
|
||||
keypairs.append(vpn_utils.create_keypair(
|
||||
self.nova_client, self.key_names[x],
|
||||
self.key_file_paths[x]))
|
||||
if self.qrouterns_compute_tuples:
|
||||
vpn_utils.delete_hosts_from_knownhosts_file(
|
||||
self.server_private_ips, self.qrouterns_compute_tuples,
|
||||
self.private_key_file)
|
||||
vpn_utils.delete_keyfiles(
|
||||
self.local_key_files, self.remote_key_files,
|
||||
self.qrouterns_compute_tuples, self.private_key_file)
|
||||
else:
|
||||
vpn_utils.delete_hosts_from_knownhosts_file(
|
||||
self.server_private_ips)
|
||||
vpn_utils.delete_keyfiles(self.local_key_files)
|
||||
|
||||
kwargs.update({
|
||||
"nics":
|
||||
[{"net-id": self.rally_networks[x]["network"]["id"]}],
|
||||
"sec_group_suffix": self.suffixes[x],
|
||||
"server_suffix": self.suffixes[x]
|
||||
})
|
||||
server = vpn_utils.create_nova_vm(
|
||||
self.nova_client, keypairs[x], **kwargs)
|
||||
self.server_private_ips.append(vpn_utils.get_server_ip(
|
||||
self.nova_client, server.id, self.suffixes[x]))
|
||||
self.servers.append(server)
|
||||
|
||||
def check_route(self):
|
||||
LOG.debug("VERIFYING THAT THERE IS A ROUTE BETWEEN ROUTER "
|
||||
"GATEWAYS")
|
||||
for ns in self.snat_namespaces:
|
||||
for ip in self.rally_router_gw_ips:
|
||||
assert(True == vpn_utils.ping(ns, ip)), (
|
||||
"PING FAILED FROM NAMESPACE " + ns + " TO IP "
|
||||
+ ip)
|
||||
|
||||
def update_router(self, router_id, admin_state_up=False):
|
||||
"""Updates router
|
||||
|
||||
:param router_id: router id
|
||||
:param admin_state_up: update 'admin_state_up' of the router
|
||||
:return:
|
||||
"""
|
||||
req_body = {'router': {'admin_state_up': admin_state_up}}
|
||||
self.neutron_client.update_router(router_id, req_body)
|
||||
|
||||
def create_vpn_services(self):
|
||||
with LOCK:
|
||||
for x in range(MAX_RESOURCES):
|
||||
self.vpn_services.append(self._create_vpn_service(
|
||||
self.rally_subnets[x], self.rally_routers[x],
|
||||
self.suffixes[x]))
|
||||
|
||||
def create_ipsec_site_connections(self, **kwargs):
|
||||
with LOCK:
|
||||
self.ipsec_site_connections = [
|
||||
self._create_ipsec_site_connection(0, 1, **kwargs),
|
||||
self._create_ipsec_site_connection(1, 0, **kwargs)
|
||||
]
|
||||
|
||||
def assert_statuses(self, final_status, **kwargs):
|
||||
LOG.debug("ASSERTING ACTIVE STATUSES FOR VPN-SERVICES AND "
|
||||
"VPN-CONNECTIONS")
|
||||
for x in range(MAX_RESOURCES):
|
||||
self._assert_statuses(self.ipsec_site_connections[x],
|
||||
self.vpn_services[x], final_status, **kwargs)
|
||||
|
||||
def assert_vpn_connectivity(self):
|
||||
LOG.debug("VERIFY THE VPN CONNECTIVITY")
|
||||
with LOCK:
|
||||
assert(self._verify_vpn_connection(0, 1)), "VPN CONNECTION FAILED"
|
||||
assert(self._verify_vpn_connection(1, 0)), "VPN CONNECTION FAILED"
|
||||
self._delete_ipsec_site_connections()
|
||||
self._delete_vpn_services()
|
||||
self._delete_ipsec_policy()
|
||||
self._delete_ike_policy()
|
||||
vpn_utils.delete_networks(
|
||||
self.neutron_client, self.neutron_admin_client, self.rally_routers,
|
||||
self.rally_networks, self.rally_subnets)
|
||||
if self.tenant_ids:
|
||||
vpn_utils.delete_tenants(self.keystone_client, self.tenant_ids)
|
||||
|
@ -14,17 +14,11 @@
|
||||
|
||||
import exceptions
|
||||
import os
|
||||
from oslo_config import cfg
|
||||
import paramiko
|
||||
import socket
|
||||
import stat
|
||||
import time
|
||||
|
||||
|
||||
def noop(*args, **kwargs):
|
||||
pass
|
||||
cfg.CONF.register_cli_opts = noop
|
||||
|
||||
from neutron.agent.linux import ip_lib
|
||||
from neutron.agent.linux import utils as linux_utils
|
||||
from rally.common import log as logging
|
||||
from rally.plugins.openstack.wrappers import network as network_wrapper
|
||||
from rally.task import utils as task_utils
|
||||
@ -35,13 +29,71 @@ START_CIDR = "10.2.0.0/24"
|
||||
EXT_NET_CIDR = "172.16.1.0/24"
|
||||
|
||||
|
||||
def create_network(neutron_client, neutron_admin_client,
|
||||
network_suffix, tenant_id=None):
|
||||
"""Creates neutron network, subnet, router
|
||||
def execute_cmd_over_ssh(host, cmd, private_key):
|
||||
"""Run the given command over ssh
|
||||
|
||||
Using paramiko package, it creates a connection to the given host;
|
||||
executes the required command on it and returns the output.
|
||||
:param host: Dictionary of ip, username and password
|
||||
:param cmd: Command to be run over ssh
|
||||
:param private_key: path to private key file
|
||||
:return: Output of the executed command
|
||||
"""
|
||||
LOG.debug('EXECUTE COMMAND <%s> OVER SSH', cmd)
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
k = paramiko.RSAKey.from_private_key_file(private_key)
|
||||
|
||||
try:
|
||||
|
||||
client.connect(host["ip"], username=host["username"], pkey=k)
|
||||
except paramiko.BadHostKeyException as e:
|
||||
raise exceptions.Exception(
|
||||
"BADHOSTKEY EXCEPTION WHEN CONNECTING TO %s", host["ip"], e)
|
||||
except paramiko.AuthenticationException as e:
|
||||
raise exceptions.Exception(
|
||||
"AUTHENTICATION EXCEPTION WHEN CONNECTING TO %s",
|
||||
host["ip"], e)
|
||||
except paramiko.SSHException as e:
|
||||
raise exceptions.Exception(
|
||||
"SSH EXCEPTION WHEN CONNECTING TO %s", host["ip"], e)
|
||||
except socket.error as e:
|
||||
raise exceptions.Exception(
|
||||
"SOCKET ERROR WHEN CONNECTING TO %s", host["ip"], e)
|
||||
LOG.debug("CONNECTED TO HOST <%s>", host["ip"])
|
||||
try:
|
||||
stdin, stdout, stderr = client.exec_command(cmd)
|
||||
return stdout.read().splitlines()
|
||||
except paramiko.SSHException as e:
|
||||
raise exceptions.Exception(
|
||||
"SSHEXCEPTION WHEN CONNECTING TO %s", host["ip"], e)
|
||||
finally:
|
||||
client.close()
|
||||
|
||||
|
||||
def create_tenant(keystone_client, tenant_suffix):
|
||||
"""Creates keystone tenant with a random name.
|
||||
|
||||
:param keystone_client: keystone client
|
||||
:param tenant_suffix: suffix name for the tenant
|
||||
:returns: uuid of the new tenant
|
||||
"""
|
||||
tenant_name = "rally_tenant_" + tenant_suffix
|
||||
LOG.debug("CREATING NEW TENANT %s", tenant_name)
|
||||
return keystone_client.tenants.create(tenant_name).id
|
||||
|
||||
|
||||
def create_network(neutron_client, neutron_admin_client, network_suffix,
|
||||
tenant_id=None, DVR_flag=True, ext_net_name=None):
|
||||
"""Create neutron network, subnet, router
|
||||
|
||||
:param neutron_client: neutron client
|
||||
:param neutron_admin_client: neutron_admin_client
|
||||
:param neutron_admin_client: neutron client with admin credentials
|
||||
:param network_suffix: str, suffix name of the new network
|
||||
:param tenant_id: uuid of the tenant
|
||||
:param DVR_flag: True - creates a DVR router
|
||||
False - creates a non DVR router
|
||||
:param ext_net_name: external network that is to be used
|
||||
:return: router, subnet, network, subnet_cidr
|
||||
"""
|
||||
subnet_cidr = network_wrapper.generate_cidr(start_cidr=START_CIDR)
|
||||
@ -53,15 +105,13 @@ def create_network(neutron_client, neutron_admin_client,
|
||||
network_args = {"name": network_name,
|
||||
"router:external": is_external
|
||||
}
|
||||
LOG.debug("ADDING NEW NETWORK: %s", network_name)
|
||||
|
||||
if tenant_id is not None:
|
||||
if tenant_id:
|
||||
network_args["tenant_id"] = tenant_id
|
||||
|
||||
LOG.debug("ADDING NEW NETWORK %s", network_name)
|
||||
return neutron_client.create_network({"network": network_args})
|
||||
|
||||
def _create_subnet(neutron_client, rally_network, network_suffix, cidr):
|
||||
"""Creates neutron subnet"""
|
||||
"""Create neutron subnet"""
|
||||
|
||||
network_id = rally_network["network"]["id"]
|
||||
subnet_name = "rally_subnet_" + network_suffix
|
||||
@ -70,19 +120,19 @@ def create_network(neutron_client, neutron_admin_client,
|
||||
"network_id": network_id,
|
||||
"ip_version": SUBNET_IP_VERSION
|
||||
}
|
||||
LOG.debug("ADDING SUBNET: %s", subnet_name)
|
||||
|
||||
if tenant_id is not None:
|
||||
if tenant_id:
|
||||
subnet_args["tenant_id"] = tenant_id
|
||||
|
||||
LOG.debug("ADDING SUBNET %s", subnet_name)
|
||||
return neutron_client.create_subnet({"subnet": subnet_args})
|
||||
|
||||
def _create_router(neutron_client, ext_network_id, rally_subnet):
|
||||
"""Creates router, sets the external gateway and adds router interface
|
||||
def _create_router(neutron_client, ext_network_id, rally_subnet, dvr_flag):
|
||||
"""Create router, set the external gateway and add router interface
|
||||
|
||||
:param neutron_client: neutron_client
|
||||
:param ext_network_id: uuid of the external network
|
||||
:param rally_subnet: subnet to add router interface
|
||||
:param dvr_flag: True - creates a DVR router
|
||||
False - creates a non DVR router
|
||||
:return: router
|
||||
"""
|
||||
router_name = "rally_router_" + network_suffix
|
||||
@ -90,81 +140,134 @@ def create_network(neutron_client, neutron_admin_client,
|
||||
router_args = {"name": router_name,
|
||||
"external_gateway_info": gw_info
|
||||
}
|
||||
LOG.debug("ADDING ROUTER: %s", router_name)
|
||||
LOG.debug("ADDING ROUTER INTERFACE")
|
||||
|
||||
if tenant_id is not None:
|
||||
if not dvr_flag:
|
||||
router_args["distributed"] = dvr_flag
|
||||
if tenant_id:
|
||||
router_args["tenant_id"] = 'tenant_id'
|
||||
LOG.debug("ADDING ROUTER %s", router_name)
|
||||
rally_router = neutron_client.create_router({"router": router_args})
|
||||
|
||||
rally_router = neutron_client.create_router(
|
||||
{"router": router_args})
|
||||
LOG.debug("[%s]: ADDING ROUTER INTERFACE")
|
||||
neutron_client.add_interface_router(
|
||||
rally_router['router']["id"],
|
||||
{"subnet_id": rally_subnet["subnet"]["id"]})
|
||||
return rally_router
|
||||
|
||||
def _get_external_network_id():
|
||||
"""Fetches the external network id, if external network exists"""
|
||||
def _get_external_network_id(ext_net_name):
|
||||
"""Fetch the network id for the given external network, if it exists.
|
||||
Else fetch the first external network present.
|
||||
"""
|
||||
|
||||
for network in neutron_client.list_networks()['networks']:
|
||||
if network['router:external']:
|
||||
ext_network_id = network['id']
|
||||
LOG.debug("EXTERNAL NETWORK ALREADY EXISTS")
|
||||
return ext_network_id
|
||||
ext_nets = neutron_client.list_networks(
|
||||
**{'router:external': True})['networks']
|
||||
|
||||
ext_nets_searched = [n for n in ext_nets if n['name'] == ext_net_name]
|
||||
if ext_nets_searched:
|
||||
return ext_nets_searched[0]['id']
|
||||
elif ext_nets:
|
||||
return ext_nets[0]['id']
|
||||
else:
|
||||
return None
|
||||
|
||||
def _create_external_network():
|
||||
"""Creates external network and subnet"""
|
||||
"""Creat external network and subnet"""
|
||||
|
||||
ext_net = _create_network(neutron_admin_client, "public", True)
|
||||
_create_subnet(neutron_admin_client, ext_net, "public", EXT_NET_CIDR)
|
||||
return ext_net['network']['id']
|
||||
|
||||
ext_network_id = _get_external_network_id()
|
||||
ext_network_id = _get_external_network_id(ext_net_name)
|
||||
if not ext_network_id:
|
||||
ext_network_id = _create_external_network()
|
||||
rally_network = _create_network(neutron_client, network_suffix)
|
||||
rally_subnet = _create_subnet(neutron_client, rally_network,
|
||||
network_suffix, subnet_cidr)
|
||||
rally_router = _create_router(neutron_client, ext_network_id, rally_subnet)
|
||||
rally_router = _create_router(neutron_client, ext_network_id,
|
||||
rally_subnet, DVR_flag)
|
||||
return rally_router, rally_network, rally_subnet, subnet_cidr
|
||||
|
||||
|
||||
def create_tenant(keystone_client, tenant):
|
||||
"""Creates keystone tenant with random name.
|
||||
:param tenant: create a tenant with random name
|
||||
:returns:
|
||||
"""
|
||||
return keystone_client.tenants.create(tenant)
|
||||
|
||||
|
||||
def delete_tenant(keystone_client, tenant):
|
||||
"""Deletes keystone tenant
|
||||
|
||||
:returns: delete keystone tenant instance
|
||||
"""
|
||||
if tenant:
|
||||
for id in tenant:
|
||||
keystone_client.tenants.delete(id)
|
||||
|
||||
|
||||
def create_keypair(nova_client, key_name, key_file_path):
|
||||
def create_keypair(nova_client, keypair_suffix):
|
||||
"""Create keypair
|
||||
|
||||
:param nova_client: nova_client
|
||||
:param key_name: key_name
|
||||
:param key_file_path: path to key_file
|
||||
:param keypair_suffix: sufix name for the keypair
|
||||
:return: keypair
|
||||
"""
|
||||
LOG.debug("ADDING NEW KEYPAIR")
|
||||
keypair = nova_client.keypairs.create(key_name)
|
||||
f = open(key_file_path, 'w')
|
||||
os.chmod(key_file_path, stat.S_IREAD | stat.S_IWRITE)
|
||||
f.write(keypair.private_key)
|
||||
f.close()
|
||||
keypair_name = "rally_keypair_" + keypair_suffix
|
||||
LOG.debug("CREATING A KEYPAIR %s", keypair_name)
|
||||
keypair = nova_client.keypairs.create(keypair_name)
|
||||
return keypair
|
||||
|
||||
|
||||
def create_nova_vm(nova_client, keypair, **kwargs):
|
||||
def write_key_to_local_path(keypair, local_key_file):
|
||||
"""Write the private key of the nova instance to a temp file
|
||||
|
||||
:param keypair: nova keypair
|
||||
:param local_key_file: path to private key file
|
||||
:return:
|
||||
"""
|
||||
|
||||
with open(local_key_file, 'w') as f:
|
||||
os.chmod(local_key_file, stat.S_IREAD | stat.S_IWRITE)
|
||||
f.write(keypair.private_key)
|
||||
|
||||
|
||||
def write_key_to_compute_node(keypair, local_path, remote_path, host,
|
||||
private_key):
|
||||
"""Write the private key of the nova instance to the compute node
|
||||
|
||||
First fetches the private key from the keypair and writes it to a
|
||||
temporary file in the local machine. It then sftp's the file
|
||||
to the compute host.
|
||||
|
||||
:param keypair: nova keypair
|
||||
:param local_path: path to private key file of the nova instance in the
|
||||
local machine
|
||||
:param remote_path: path where the private key file has to be placed
|
||||
in the remote machine
|
||||
:param host: compute host credentials
|
||||
:param private_key: path to your private key file
|
||||
:return:
|
||||
"""
|
||||
|
||||
LOG.debug("WRITING PRIVATE KEY TO COMPUTE NODE")
|
||||
k = paramiko.RSAKey.from_private_key_file(private_key)
|
||||
write_key_to_local_path(keypair, local_path)
|
||||
try:
|
||||
transport = paramiko.Transport(host['ip'], host['port'])
|
||||
except paramiko.SSHException as e:
|
||||
raise exceptions.Exception(
|
||||
"PARAMIKO TRANSPORT FAILED. CHECK IF THE HOST IP %s AND PORT %s "
|
||||
"ARE CORRECT %s", host['ip'], host['port'], e)
|
||||
try:
|
||||
transport.connect(
|
||||
username=host['username'], pkey=k)
|
||||
except paramiko.BadHostKeyException as e:
|
||||
transport.close()
|
||||
raise exceptions.Exception(
|
||||
"BADHOSTKEY EXCEPTION WHEN CONNECTING TO %s", host["ip"], e)
|
||||
except paramiko.AuthenticationException as e:
|
||||
transport.close()
|
||||
raise exceptions.Exception(
|
||||
"AUTHENTICATION EXCEPTION WHEN CONNECTING TO %s",
|
||||
host["ip"], e)
|
||||
except paramiko.SSHException as e:
|
||||
transport.close()
|
||||
raise exceptions.Exception(
|
||||
"SSH EXCEPTION WHEN CONNECTING TO %s", host["ip"], e)
|
||||
LOG.debug("CONNECTED TO HOST <%s>", host["ip"])
|
||||
|
||||
try:
|
||||
sftp_client = paramiko.SFTPClient.from_transport(transport)
|
||||
sftp_client.put(local_path, remote_path)
|
||||
except IOError as e:
|
||||
raise exceptions.Exception("FILE PATH DOESN'T EXIST", e)
|
||||
finally:
|
||||
transport.close()
|
||||
|
||||
|
||||
def create_server(nova_client, keypair, **kwargs):
|
||||
"""Create nova instance
|
||||
|
||||
:param nova_client: nova client
|
||||
@ -172,10 +275,10 @@ def create_nova_vm(nova_client, keypair, **kwargs):
|
||||
:return: new nova instance
|
||||
"""
|
||||
# add sec-group
|
||||
sec_group_suffix = "rally_secgroup_" + kwargs["sec_group_suffix"]
|
||||
LOG.debug("ADDING NEW SECURITY GROUP %s", sec_group_suffix)
|
||||
secgroup = nova_client.security_groups.create(sec_group_suffix,
|
||||
sec_group_suffix)
|
||||
sec_group_name = "rally_secgroup_" + kwargs["sec_group_suffix"]
|
||||
LOG.debug("ADDING NEW SECURITY GROUP %s", sec_group_name)
|
||||
secgroup = nova_client.security_groups.create(sec_group_name,
|
||||
sec_group_name)
|
||||
# add security rules for SSH and ICMP
|
||||
nova_client.security_group_rules.create(secgroup.id, from_port=22,
|
||||
to_port=22, ip_protocol="tcp", cidr="0.0.0.0/0")
|
||||
@ -186,14 +289,23 @@ def create_nova_vm(nova_client, keypair, **kwargs):
|
||||
# boot new nova instance
|
||||
server_name = "rally_server_" + (kwargs["server_suffix"])
|
||||
LOG.debug("BOOTING NEW INSTANCE: %s", server_name)
|
||||
LOG.debug("%s", kwargs["image"])
|
||||
server = nova_client.servers.create(server_name,
|
||||
image=kwargs["image"],
|
||||
flavor=kwargs["flavor"],
|
||||
key_name=keypair.name,
|
||||
security_groups=[secgroup.id],
|
||||
nics=kwargs["nics"])
|
||||
return server
|
||||
|
||||
LOG.debug("WAITING FOR INSTANCE TO BECOME ACTIVE")
|
||||
|
||||
def assert_server_status(server, **kwargs):
|
||||
"""Assert server status
|
||||
|
||||
:param server: nova server
|
||||
"""
|
||||
|
||||
LOG.debug('WAITING FOR SERVER TO GO ACTIVE')
|
||||
server = task_utils.wait_for(
|
||||
server,
|
||||
is_ready=task_utils.resource_is("ACTIVE"),
|
||||
@ -201,10 +313,7 @@ def create_nova_vm(nova_client, keypair, **kwargs):
|
||||
timeout=kwargs["nova_server_boot_timeout"],
|
||||
check_interval=5)
|
||||
LOG.debug("SERVER STATUS: %s", server.status)
|
||||
|
||||
assert('ACTIVE' == server.status), (
|
||||
"THE INSTANCE IS NOT IN ACTIVE STATE")
|
||||
return server
|
||||
assert('ACTIVE' == server.status), ("THE INSTANCE IS NOT IN ACTIVE STATE")
|
||||
|
||||
|
||||
def get_server_ip(nova_client, server_id, network_suffix):
|
||||
@ -221,167 +330,237 @@ def get_server_ip(nova_client, server_id, network_suffix):
|
||||
return server_ip
|
||||
|
||||
|
||||
def get_namespace():
|
||||
"""Get namespaces
|
||||
def add_floating_ip(nova_client, server):
|
||||
"""Associates floating-ip to a server
|
||||
|
||||
:param nova_client: nova client
|
||||
:param server: nova instance
|
||||
:return: associated floating ip
|
||||
"""
|
||||
|
||||
fip_list = nova_client.floating_ips.list()
|
||||
for fip in fip_list:
|
||||
if fip.instance_id is None:
|
||||
floating_ip = fip
|
||||
break
|
||||
else:
|
||||
LOG.debug("CREATING NEW FLOATING IP")
|
||||
floating_ip = nova_client.floating_ips.create()
|
||||
LOG.debug("ASSOCIATING FLOATING IP %s", floating_ip.ip)
|
||||
nova_client.servers.add_floating_ip(server.id, floating_ip.ip)
|
||||
return floating_ip
|
||||
|
||||
|
||||
def get_namespace(host, private_key):
|
||||
"""SSH into the host and get the namespaces
|
||||
|
||||
:param host : dictionary of controller/compute node credentials
|
||||
{ip:x.x.x.x, username:xxx, password:xxx}
|
||||
:param private_key: path to private key file
|
||||
:return: namespaces
|
||||
"""
|
||||
LOG.debug("GET NAMESPACES USING 'ip netns'")
|
||||
cmd = ['ip', 'netns']
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd)
|
||||
try:
|
||||
namespaces = linux_utils.execute(cmd)
|
||||
except RuntimeError:
|
||||
return None
|
||||
LOG.debug("%s", namespaces)
|
||||
LOG.debug("GET NAMESPACES")
|
||||
cmd = "sudo ip netns"
|
||||
namespaces = execute_cmd_over_ssh(host, cmd, private_key)
|
||||
LOG.debug("NAMESPACES %s", namespaces)
|
||||
return namespaces
|
||||
|
||||
|
||||
def wait_for_namespace_creation(namespace, rally_router, **kwargs):
|
||||
"""Wait for namespace creation
|
||||
def wait_for_namespace_creation(namespace_tag, router_id, hosts, private_key,
|
||||
timeout=60):
|
||||
"""Wait for the namespace creation
|
||||
|
||||
:param namespace: snat/qrouter namespace
|
||||
:param rally_router: rally_router
|
||||
Get into each of the controllers/compute nodes and check which one contains
|
||||
the snat/qrouter namespace corresponding to rally_router. Sleep for a sec
|
||||
and repeat until either the namespace is found or the namespace_creation_
|
||||
time exceeded.
|
||||
:param namespace_tag: which namespace ("snat_" or "qrouter_")
|
||||
:param router_id: uuid of the rally_router
|
||||
:param hosts: controllers or compute hosts
|
||||
:param private_key: path to private key file
|
||||
:param timeout: namespace creation time
|
||||
:return:
|
||||
"""
|
||||
start_time = time.time()
|
||||
while True:
|
||||
namespaces = get_namespace().split()
|
||||
for line in namespaces:
|
||||
if line == (namespace + rally_router["router"]["id"]):
|
||||
namespace = line
|
||||
return namespace
|
||||
for host in hosts:
|
||||
namespaces = get_namespace(host, private_key)
|
||||
for line in namespaces:
|
||||
if line == (namespace_tag + router_id):
|
||||
namespace_tag = line
|
||||
return namespace_tag, host
|
||||
time.sleep(1)
|
||||
if time.time() - start_time > kwargs['namespace_creation_timeout']:
|
||||
raise exceptions.Exception("Timeout while waiting for"
|
||||
" namespaces to be created")
|
||||
if time.time() - start_time > timeout:
|
||||
raise exceptions.Exception("TIMEOUT WHILE WAITING FOR"
|
||||
" NAMESPACES TO BE CREATED")
|
||||
|
||||
|
||||
def ping(namespace, ip):
|
||||
"""Pings ip address from network namespace.
|
||||
|
||||
In order to ping it uses following cli command:
|
||||
ip netns exec <namespace> ping -c 4 -q <ip>
|
||||
:param namespace: namespace
|
||||
:param ip: ip to ping to
|
||||
"""
|
||||
LOG.debug("PING %s FROM THE NAMESPACE %s", ip, namespace)
|
||||
count = 4
|
||||
cmd = ['ping', '-w', 2 * count, '-c', count, ip]
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||
try:
|
||||
ping_result = linux_utils.execute(cmd, run_as_root=True)
|
||||
except RuntimeError:
|
||||
def ping(host, cmd, private_key):
|
||||
"""Execute ping command over ssh"""
|
||||
ping_result = execute_cmd_over_ssh(host, cmd, private_key)
|
||||
if ping_result:
|
||||
LOG.debug("PING RESULT %s", ping_result)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
LOG.debug("%s", ping_result)
|
||||
return True
|
||||
|
||||
|
||||
def get_interfaces(namespace):
|
||||
"""Do an "ip a".
|
||||
def ping_router_gateway(namespace_controller_tuple, router_gw_ip, private_key):
|
||||
"""Ping the ip address from network namespace
|
||||
|
||||
In order to do "ip a" it uses following cli command:
|
||||
ip netns exec <namespace> ip a | grep qg
|
||||
:param namespace: namespace
|
||||
Get into controller's snat-namespaces and ping the peer router gateway ip.
|
||||
:param namespace_controller_tuple: namespace, controller tuple. (It's the
|
||||
controller that contains the namespace )
|
||||
:param router_gw_ip: ip address to be pinged
|
||||
:param private_key: path to private key file
|
||||
:return: True if ping succeeds
|
||||
False if ping fails
|
||||
"""
|
||||
namespace, controller = namespace_controller_tuple
|
||||
LOG.debug("PING %s FROM THE NAMESPACE %s", router_gw_ip, namespace)
|
||||
count = 4
|
||||
cmd = "sudo ip netns exec {} ping -w {} -c {} {}".format(
|
||||
namespace, 2 * count, count, router_gw_ip)
|
||||
return ping(controller, cmd, private_key)
|
||||
|
||||
|
||||
def get_interfaces(namespace_controller_tuple, private_key):
|
||||
"""Get the interfaces
|
||||
|
||||
Get into the controller's snat namespace and list the interfaces.
|
||||
:param namespace_controller_tuple: namespace, controller tuple(the
|
||||
controller that contains the namespace).
|
||||
:param private_key: path to private key file
|
||||
:return: interfaces
|
||||
"""
|
||||
namespace, controller = namespace_controller_tuple
|
||||
LOG.debug("GET THE INTERFACES BY USING 'ip a' FROM THE NAMESPACE %s",
|
||||
namespace)
|
||||
cmd = ['ip', 'a']
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||
try:
|
||||
interfaces = linux_utils.execute(cmd, run_as_root=True)
|
||||
except RuntimeError:
|
||||
return None
|
||||
LOG.debug("%s", interfaces)
|
||||
cmd = "sudo ip netns exec {} ip a".format(namespace)
|
||||
interfaces = execute_cmd_over_ssh(controller, cmd, private_key)
|
||||
LOG.debug("INTERFACES %s", interfaces)
|
||||
return interfaces
|
||||
|
||||
|
||||
def start_tcpdump(namespace, interface):
|
||||
"""Starts tcpdump at the given interface
|
||||
def start_tcpdump(namespace_controller_tuple, interface, private_key):
|
||||
"""Start the tcpdump at the given interface
|
||||
|
||||
In order to start a "tcpdump" it uses the following command:
|
||||
ip netns exec <namespace> sudo tcpdump -i <interface>
|
||||
:param namespace: namespace
|
||||
:param interface: interface
|
||||
:return: tcpdump
|
||||
Get into the controller's snat namespace and start a tcp dump at the
|
||||
qg-interface.
|
||||
:param namespace_controller_tuple: namespace, controller tuple. (It's the
|
||||
controller that contains the namespace )
|
||||
:param interface: interface in which tcpdump has to be run
|
||||
:param private_key: path to private key file
|
||||
:return: tcpdump output
|
||||
"""
|
||||
LOG.debug("START THE TCPDUMP USING 'tcpdump -i <%s> FROM THE NAMESPACE"
|
||||
namespace, controller = namespace_controller_tuple
|
||||
LOG.debug("START THE TCPDUMP USING 'tcpdump -i %s FROM THE NAMESPACE"
|
||||
" %s", interface, namespace)
|
||||
cmd = ['timeout', '5', 'tcpdump', '-n', '-i', interface]
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||
try:
|
||||
tcpdump = linux_utils.execute(cmd, run_as_root=True,
|
||||
extra_ok_codes=[124])
|
||||
except RuntimeError:
|
||||
return None
|
||||
LOG.debug("%s", tcpdump)
|
||||
cmd = ("sudo ip netns exec {} timeout 15 tcpdump -n -i {}"
|
||||
.format(namespace, interface))
|
||||
tcpdump = execute_cmd_over_ssh(controller, cmd, private_key)
|
||||
LOG.debug("TCPDUMP %s", tcpdump)
|
||||
return tcpdump
|
||||
|
||||
|
||||
def ssh_and_ping_server(ssh_server, ping_server, namespace, key_file_name):
|
||||
"""SSH into the server from the namespace.
|
||||
def ssh_and_ping_server(local_server, peer_server, ns_compute_tuple, keyfile,
|
||||
private_key):
|
||||
"""SSH and ping the nova instance from the namespace
|
||||
|
||||
In order to ssh it uses the following command:
|
||||
ip netns exec <namespace> ssh -i <path to keyfile> cirros@<server_ip>
|
||||
:param ssh_server: ip of the server to ssh into
|
||||
:param ping_server: ip of the server to ping to
|
||||
:param namespace: qrouter namespace
|
||||
:param key_file_name: path to private key file
|
||||
:return: True/False
|
||||
Get into the compute node's qrouter namespace and then ssh into the local
|
||||
nova instance & ping the peer nova instance.
|
||||
:param local_server: private ip of the server to ssh into
|
||||
:param peer_server: private ip of the server to ping to
|
||||
:param ns_compute_tuple: namespace, compute tuple. (It's the
|
||||
compute node that contains the namespace )
|
||||
:param keyfile: path to private key file of the nova instance
|
||||
:param private_key: path to private key file
|
||||
:return: True if ping succeeds
|
||||
False if ping fails
|
||||
"""
|
||||
namespace, compute_host = ns_compute_tuple
|
||||
LOG.debug("SSH INTO SERVER %s AND PING THE PEER SERVER %s FROM THE"
|
||||
" NAMESPACE %s", ssh_server, ping_server, namespace)
|
||||
host = "cirros@" + ssh_server
|
||||
" NAMESPACE %s", local_server, peer_server, namespace)
|
||||
host = "cirros@" + local_server
|
||||
count = 20
|
||||
cmd = ['ssh', '-o', 'StrictHostKeyChecking=no', '-o', 'HashKnownHosts=no',
|
||||
'-i', key_file_name, host, 'ping', '-w', 2 * count, '-c', count,
|
||||
ping_server]
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||
try:
|
||||
ping_result = linux_utils.execute(cmd, run_as_root=True)
|
||||
except RuntimeError:
|
||||
return False
|
||||
LOG.debug("%s", ping_result)
|
||||
return True
|
||||
cmd = ("sudo ip netns exec {} ssh -v -o StrictHostKeyChecking=no -o"
|
||||
"HashKnownHosts=no -i {} {} ping -w {} -c {} {}"
|
||||
.format(namespace, keyfile, host, 2 * count, count, peer_server))
|
||||
return ping(compute_host, cmd, private_key)
|
||||
|
||||
|
||||
def ssh_and_ping_server_with_fip(local_server, peer_server, keyfile,
|
||||
private_key):
|
||||
"""SSH into the local nova instance and ping the peer instance using fips
|
||||
|
||||
:param local_server: fip of the server to ssh into
|
||||
:param peer_server: private ip of the server to ping to
|
||||
:param keyfile: path to private key file of the nova instance
|
||||
:param private_key: path to private key file
|
||||
:return: True if ping succeeds
|
||||
False if ping fails
|
||||
"""
|
||||
LOG.debug("SSH INTO LOCAL SERVER %s AND PING THE PEER SERVER %s",
|
||||
local_server.ip, peer_server)
|
||||
count = 20
|
||||
local_host = {"ip": "127.0.0.1", "username": None}
|
||||
host = "cirros@" + local_server.ip
|
||||
cmd = ("ssh -v -o StrictHostKeyChecking=no -o"
|
||||
"HashKnownHosts=no -i {} {} ping -w {} -c {} {}"
|
||||
.format(keyfile, host, 2 * count, count, peer_server))
|
||||
return ping(local_host, cmd, private_key)
|
||||
|
||||
|
||||
def delete_servers(nova_client, servers):
|
||||
"""Delete nova servers
|
||||
|
||||
It deletes the nova servers, associated security groups and keypairs.
|
||||
It deletes the nova servers, associated security groups.
|
||||
|
||||
:param nova_client: nova client
|
||||
:param servers: nova instances to be deleted
|
||||
:return:
|
||||
"""
|
||||
if servers:
|
||||
for server in servers:
|
||||
if "rally" in server.name:
|
||||
sec_group_name = server.security_groups[0]['name']
|
||||
server_key_name = server.key_name
|
||||
for server in servers:
|
||||
LOG.debug("DELETING NOVA INSTANCE: %s", server.id)
|
||||
sec_group_id = server.security_groups[0]['name']
|
||||
nova_client.servers.delete(server.id)
|
||||
|
||||
LOG.debug("DELETING NOVA INSTANCE: %s", server.id)
|
||||
nova_client.servers.delete(server.id)
|
||||
LOG.debug("WAITING FOR INSTANCE TO GET DELETED")
|
||||
task_utils.wait_for_delete(
|
||||
server, update_resource=task_utils.get_from_manager())
|
||||
|
||||
LOG.debug("WAITING FOR INSTANCE TO GET DELETED")
|
||||
task_utils.wait_for_delete(
|
||||
server, update_resource=task_utils.get_from_manager())
|
||||
|
||||
for secgroup in nova_client.security_groups.list():
|
||||
if secgroup.name == sec_group_name:
|
||||
LOG.debug("DELETING SEC_GROUP: %s", sec_group_name)
|
||||
nova_client.security_groups.delete(secgroup.id)
|
||||
|
||||
for key_pair in nova_client.keypairs.list():
|
||||
if key_pair.name == server_key_name:
|
||||
LOG.debug("DELETING KEY_PAIR: %s", server_key_name)
|
||||
nova_client.keypairs.delete(key_pair.id)
|
||||
for secgroup in nova_client.security_groups.list():
|
||||
if secgroup.id == sec_group_id:
|
||||
LOG.debug("DELETING SEC_GROUP: %s", sec_group_id)
|
||||
nova_client.security_groups.delete(secgroup.id)
|
||||
|
||||
|
||||
def delete_network(neutron_client, neutron_admin_client,
|
||||
def delete_floating_ips(nova_client, fips):
|
||||
"""Delete floating ips
|
||||
|
||||
:param nova_client: nova client
|
||||
:param fips: list of floating ips
|
||||
:return:
|
||||
"""
|
||||
for fip in fips:
|
||||
nova_client.floating_ips.delete(fip.id)
|
||||
|
||||
|
||||
def delete_keypairs(nova_client, keypairs):
|
||||
"""Delete key pairs
|
||||
|
||||
:param nova_client: nova client
|
||||
:param keypairs: list of keypairs
|
||||
:return
|
||||
"""
|
||||
for key_pair in keypairs:
|
||||
LOG.debug("DELETING KEY_PAIR %s", key_pair.name)
|
||||
nova_client.keypairs.delete(key_pair.id)
|
||||
|
||||
|
||||
def delete_networks(neutron_client, neutron_admin_client,
|
||||
routers, networks, subnets):
|
||||
"""Delete neutron network, subnets amd routers.
|
||||
"""Delete neutron network, subnets amd routers
|
||||
|
||||
:param neutron_client: neutron client
|
||||
:param neutron_admin_client: neutron_admin_client
|
||||
@ -391,64 +570,87 @@ def delete_network(neutron_client, neutron_admin_client,
|
||||
:return
|
||||
"""
|
||||
LOG.debug("DELETING RALLY ROUTER INTERFACES & GATEWAYS")
|
||||
if routers:
|
||||
for router in routers:
|
||||
if "rally" in router['router']['name']:
|
||||
neutron_client.remove_gateway_router(router['router']['id'])
|
||||
router_name = router['router']['name']
|
||||
subnet_name = ("rally_subnet_" +
|
||||
router_name[13:len(router_name)])
|
||||
if subnets:
|
||||
for subnet in subnets:
|
||||
if subnet_name == subnet['subnet']['name']:
|
||||
neutron_client.remove_interface_router(
|
||||
router['router']['id'],
|
||||
{"subnet_id": subnet['subnet']['id']})
|
||||
for router in routers:
|
||||
neutron_client.remove_gateway_router(router['router']['id'])
|
||||
router_name = router['router']['name']
|
||||
subnet_name = ("rally_subnet_" + router_name[13:len(router_name)])
|
||||
for subnet in subnets:
|
||||
if subnet_name == subnet['subnet']['name']:
|
||||
neutron_client.remove_interface_router(
|
||||
router['router']['id'],
|
||||
{"subnet_id": subnet['subnet']['id']})
|
||||
|
||||
LOG.debug("DELETING RALLY ROUTERS")
|
||||
if routers:
|
||||
for router in routers:
|
||||
if "rally" in router['router']['name']:
|
||||
neutron_client.delete_router(router['router']['id'])
|
||||
for router in routers:
|
||||
neutron_client.delete_router(router['router']['id'])
|
||||
|
||||
LOG.debug("DELETING RALLY NETWORKS")
|
||||
if networks:
|
||||
for network in networks:
|
||||
if (network['network']['router:external'] and
|
||||
network['network']['name'] == "rally_network_public"):
|
||||
external_network = network
|
||||
neutron_admin_client.delete_network(
|
||||
external_network['network']["id"])
|
||||
if "rally_network" in network['network']['name']:
|
||||
neutron_client.delete_network(network['network']['id'])
|
||||
for network in networks:
|
||||
if (network['network']['router:external'] and
|
||||
network['network']['name'] == "rally_network_public"):
|
||||
external_network = network
|
||||
neutron_admin_client.delete_network(
|
||||
external_network['network']["id"])
|
||||
elif network['network']['router:external']:
|
||||
pass
|
||||
else:
|
||||
neutron_client.delete_network(network['network']['id'])
|
||||
|
||||
|
||||
def delete_key_files(key_file_paths):
|
||||
"""Deletes ssh key files
|
||||
def delete_tenants(keystone_client, tenant_ids):
|
||||
"""Delete keystone tenant
|
||||
|
||||
:param key_file_paths: paths to ssh key files
|
||||
:param keystone_client: keystone client
|
||||
:param tenant_ids: list of tenants' uuids
|
||||
:returns: delete keystone tenant instance
|
||||
"""
|
||||
LOG.debug('DELETE TENANTS')
|
||||
for id in tenant_ids:
|
||||
keystone_client.tenants.delete(id)
|
||||
|
||||
|
||||
def delete_keyfiles(local_key_files, remote_key_files=None,
|
||||
ns_compute_tuples=None, private_key=None):
|
||||
"""Delete the SSH keyfiles from the compute and the local nodes
|
||||
|
||||
:param local_key_files: paths to ssh key files in local node
|
||||
:param remote_key_files: paths to ssh key files in compute nodes
|
||||
:param ns_compute_tuples: namespace, compute tuple. (It's the
|
||||
compute node that contains the namespace )
|
||||
:param private_key: path to private key file
|
||||
:return:
|
||||
"""
|
||||
LOG.debug("DELETING RALLY KEY FILES")
|
||||
if key_file_paths:
|
||||
for path in key_file_paths:
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
LOG.debug("DELETING RALLY KEY FILES FROM LOCAL MACHINE")
|
||||
for key in local_key_files:
|
||||
if os.path.exists(key):
|
||||
os.remove(key)
|
||||
|
||||
if ns_compute_tuples:
|
||||
LOG.debug("DELETING RALLY KEY FILES FROM COMPUTE HOSTS")
|
||||
for key, ns_comp in zip(remote_key_files, ns_compute_tuples):
|
||||
cmd = "sudo rm -f {}".format(key)
|
||||
host = ns_comp[1]
|
||||
execute_cmd_over_ssh(host, cmd, private_key)
|
||||
|
||||
|
||||
def delete_hosts_from_knownhosts_file(hosts):
|
||||
"""Removes the hosts from the knownhosts file
|
||||
def delete_hosts_from_knownhosts_file(hosts, ns_compute_tuples=None,
|
||||
private_key=None):
|
||||
"""Remove the hosts from the knownhosts file
|
||||
|
||||
:param hosts: host ips to be removed from /root/.ssh/knownhosts
|
||||
:param ns_compute_tuples: namespace, compute tuple. (It's the
|
||||
compute node that contains the namespace )
|
||||
:param private_key: path to private key file
|
||||
:return:
|
||||
"""
|
||||
LOG.debug("DELETES HOSTS FROM THE KNOWNHOSTS FILE")
|
||||
if hosts:
|
||||
if ns_compute_tuples:
|
||||
LOG.debug("DELETES HOSTS FROM THE KNOWNHOSTS FILE")
|
||||
for host, ns_comp in zip(hosts, ns_compute_tuples):
|
||||
compute_host = ns_comp[1]
|
||||
cmd = ("sudo ssh-keygen -f /root/.ssh/known_hosts -R"
|
||||
" {}".format(host))
|
||||
execute_cmd_over_ssh(compute_host, cmd, private_key)
|
||||
else:
|
||||
for host in hosts:
|
||||
cmd = ['ssh-keygen', '-f', "/root/.ssh/known_hosts", '-R', host]
|
||||
cmd = ip_lib.add_namespace_to_cmd(cmd)
|
||||
try:
|
||||
linux_utils.execute(cmd, run_as_root=True)
|
||||
except RuntimeError:
|
||||
return False
|
||||
return True
|
||||
os.system("sudo ssh-keygen -f /root/.ssh/known_hosts -R"
|
||||
" {}".format(host))
|
||||
|
17
rally-jobs/rally-configs/args_template.json
Normal file
17
rally-jobs/rally-configs/args_template.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"image_name": "^cirros.*-disk$",
|
||||
"private_key": "<path-to-private-key-file>",
|
||||
"controller_creds": [
|
||||
{
|
||||
"ip": "x.x.x.x",
|
||||
"username": "xxx"
|
||||
}
|
||||
],
|
||||
"compute_creds": [
|
||||
{
|
||||
"ip": "x.x.x.x",
|
||||
"username": "xxx",
|
||||
"port": 22
|
||||
}
|
||||
]
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{% set image_name = image_name or "cirros-0.3.3-x86_64-disk" %}
|
||||
---
|
||||
VpnBasicScenario.create_and_delete_vpn_connection:
|
||||
|
||||
TestVpnBasicScenario.create_and_delete_vpn_connection:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
@ -19,8 +19,14 @@
|
||||
secret: "secret"
|
||||
nova_server_boot_timeout: 60 * 6
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 400
|
||||
ipsec_site_connection_creation_timeout: 180
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: True
|
||||
use_admin_client: False
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
||||
@ -35,7 +41,7 @@
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
TestVPNStatusScenario.check_vpn_status:
|
||||
TestVpnStatusScenario.check_vpn_status:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
@ -46,6 +52,12 @@
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 400
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: True
|
||||
use_admin_client: False
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
||||
@ -60,7 +72,7 @@
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
VpnTenantScenario.multitenants_vpn_test:
|
||||
TestVpnTenantScenario.multitenants_vpn_test:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
@ -69,8 +81,14 @@
|
||||
name: {{image_name}}
|
||||
nova_server_boot_timeout: 60 * 6
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 400
|
||||
ipsec_site_connection_creation_timeout: 180
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: True
|
||||
use_admin_client: True
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
103
rally-jobs/rally-configs/rally_config_non_dvr.yaml
Normal file
103
rally-jobs/rally-configs/rally_config_non_dvr.yaml
Normal file
@ -0,0 +1,103 @@
|
||||
---
|
||||
TestVpnBasicScenario.create_and_delete_vpn_connection:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
name: {{image_name}}
|
||||
phase1_negotiation_mode: "main"
|
||||
auth_algorithm: "sha1"
|
||||
encryption_algorithm: "aes-128"
|
||||
pfs: "group5"
|
||||
value: 7200
|
||||
ike_version: "v1"
|
||||
transform_protocol: "esp"
|
||||
encapsulation_mode: "tunnel"
|
||||
mtu: 1500
|
||||
secret: "secret"
|
||||
nova_server_boot_timeout: 60 * 6
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 180
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: False
|
||||
use_admin_client: True
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
TestVpnStatusScenario.check_vpn_status:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
name: {{image_name}}
|
||||
nova_server_boot_timeout: 60 * 6
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 400
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: False
|
||||
use_admin_client: True
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
TestVpnTenantScenario.multitenants_vpn_test:
|
||||
-
|
||||
args:
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
name: {{image_name}}
|
||||
nova_server_boot_timeout: 60 * 6
|
||||
vpn_service_creation_timeout: 100
|
||||
ipsec_site_connection_creation_timeout: 180
|
||||
namespace_creation_timeout: 60
|
||||
private_key: {{private_key}}
|
||||
controller_creds: {{controller_creds}}
|
||||
compute_creds: {{compute_creds}}
|
||||
DVR_flag: False
|
||||
use_admin_client: True
|
||||
ext-net: "ext-net"
|
||||
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 1
|
||||
concurrency: 1
|
||||
|
||||
context:
|
||||
users:
|
||||
tenants: 1
|
||||
users_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
Loading…
Reference in New Issue
Block a user