aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfmenguy <francoisregis.menguy@orange.com>2019-01-09 11:22:50 +0100
committerfmenguy <francoisregis.menguy@orange.com>2019-01-10 15:15:05 +0100
commit6f7847f5917a80d224031bb92b63530fe4965734 (patch)
tree3c517e215ea0cd385194d727c846488c317a5091
parent0d70709b1e56d7dae02411802730585af6bb071e (diff)
NFVBENCH-120 No admin support patchHEAD3.0.5master
Change-Id: Iaaf29e4eb439243348e955e796b6f951c184ee19 Signed-off-by: fmenguy <francoisregis.menguy@orange.com>
-rwxr-xr-xnfvbench/cfg.default.yaml13
-rw-r--r--nfvbench/chaining.py34
-rw-r--r--nfvbench/credentials.py15
-rw-r--r--test/test_chains.py72
4 files changed, 125 insertions, 9 deletions
diff --git a/nfvbench/cfg.default.yaml b/nfvbench/cfg.default.yaml
index fa3d807..c2fa29e 100755
--- a/nfvbench/cfg.default.yaml
+++ b/nfvbench/cfg.default.yaml
@@ -25,6 +25,11 @@
# The only case where this field can be empty is when measuring a system that does not run
# OpenStack or when OpenStack APIs are not accessible or OpenStack APis use is not
# desirable. In that case the EXT service chain must be used.
+#
+# If openrc is not admin some parameters are mandatory and must be filled with valid values in config file such as :
+# - availability_zone
+# - hypervisor_hostname
+# - vlans
openrc_file:
# Forwarder to use in nfvbenchvm image. Available options: ['vpp', 'testpmd']
@@ -66,11 +71,15 @@ flavor:
# Name of the availability zone to use for the test VMs
# Must be one of the zones listed by 'nova availability-zone-list'
# availability_zone: 'nova'
+# If openrc is not admin set a valid value
availability_zone:
# To force placement on a given hypervisor, set the name here
# (if multiple names are provided, the first will be used)
# Leave empty to let openstack pick the hypervisor
compute_nodes:
+# If openrc is not admin set a valid value for hypervisor hostname
+# Example of value: hypervisor_hostname: "server1"
+hypervisor_hostname:
# Type of service chain to run, possible options are PVP, PVVP and EXT
# PVP - port to VM to port
@@ -192,7 +201,7 @@ traffic_generator:
#
# Generator profiles are listed in the following format:
# `name`: Traffic generator profile name (use a unique name, no space or special character)
- # DFo not change this field
+ # Do not change this field
# `tool`: Traffic generator tool to be used (currently supported is `TRex`).
# Do not change this field
# `ip`: IP address of the traffic generator.
@@ -369,7 +378,7 @@ vxlan: false
# is not supported). Use the vtep_vlan option to enable vlan tagging for the VxLAN overlay network.
vlan_tagging: true
-# Used only in the case of EXT chain and no openstack to specify the VLAN IDs to use.
+# Used only in the case of EXT chain and no openstack or not admin access to specify the VLAN IDs to use.
# This property is ignored when OpenStakc is used or in the case of l2-loopback.
# If OpenStack is used leave the list empty, VLAN IDs are retrieved from OpenStack networks using Neutron API.
# If networks are shared across all chains (service_chain_shared_net=true), the list should have exactly 2 values
diff --git a/nfvbench/chaining.py b/nfvbench/chaining.py
index a97cd0b..1a977da 100644
--- a/nfvbench/chaining.py
+++ b/nfvbench/chaining.py
@@ -522,7 +522,13 @@ class ChainVnf(object):
def get_hostname(self):
"""Get the hypervisor host name running this VNF instance."""
- return getattr(self.instance, 'OS-EXT-SRV-ATTR:hypervisor_hostname')
+ if self.manager.is_admin:
+ hypervisor_hostname = getattr(self.instance, 'OS-EXT-SRV-ATTR:hypervisor_hostname')
+ else:
+ hypervisor_hostname = self.manager.config.hypervisor_hostname
+ if not hypervisor_hostname:
+ raise ChainException('Hypervisor hostname parameter is mandatory')
+ return hypervisor_hostname
def get_host_ip(self):
"""Get the IP address of the host where this instance runs.
@@ -536,7 +542,12 @@ class ChainVnf(object):
def get_hypervisor_name(self):
"""Get hypervisor name (az:hostname) for this VNF instance."""
if self.instance:
- az = getattr(self.instance, 'OS-EXT-AZ:availability_zone')
+ if self.manager.is_admin:
+ az = getattr(self.instance, 'OS-EXT-AZ:availability_zone')
+ else:
+ az = self.manager.config.availability_zone
+ if not az:
+ raise ChainException('Availability zone parameter is mandatory')
hostname = self.get_hostname()
if az:
return az + ':' + hostname
@@ -851,6 +862,7 @@ class ChainManager(object):
if self.openstack:
# openstack only
session = chain_runner.cred.get_session()
+ self.is_admin = chain_runner.cred.is_admin
self.nova_client = Client(2, session=session)
self.neutron_client = neutronclient.Client('2.0', session=session)
self.glance_client = glanceclient.Client('2', session=session)
@@ -877,12 +889,14 @@ class ChainManager(object):
else:
# Make sure all instances are active before proceeding
self._ensure_instances_active()
+ # network API call do not show VLANS ID if not admin read from config
+ if not self.is_admin:
+ self._get_config_vlans()
except Exception:
self.delete()
raise
else:
# no openstack, no need to create chains
-
if not config.l2_loopback and config.no_arp:
self._get_dest_macs_from_config()
if config.vlan_tagging:
@@ -890,12 +904,18 @@ class ChainManager(object):
if len(config.vlans) != 2:
raise ChainException('The config vlans property must be a list '
'with 2 lists of VLAN IDs')
- re_vlan = "[0-9]*$"
- self.vlans = [self._check_list('vlans[0]', config.vlans[0], re_vlan),
- self._check_list('vlans[1]', config.vlans[1], re_vlan)]
+ self._get_config_vlans()
if config.vxlan:
raise ChainException('VxLAN is only supported with OpenStack')
+ def _get_config_vlans(self):
+ re_vlan = "[0-9]*$"
+ try:
+ self.vlans = [self._check_list('vlans[0]', self.config.vlans[0], re_vlan),
+ self._check_list('vlans[1]', self.config.vlans[1], re_vlan)]
+ except IndexError:
+ raise ChainException('vlans parameter is mandatory. Set valid value in config file')
+
def _get_dest_macs_from_config(self):
re_mac = "[0-9a-fA-F]{2}([-:])[0-9a-fA-F]{2}(\\1[0-9a-fA-F]{2}){4}$"
tg_config = self.config.traffic_generator
@@ -1114,7 +1134,7 @@ class ChainManager(object):
port_index: left port is 0, right port is 1
return: a VLAN ID list indexed by the chain index or None if no vlan tagging
"""
- if self.chains:
+ if self.chains and self.is_admin:
return [self.chains[chain_index].get_vlan(port_index)
for chain_index in range(self.chain_count)]
# no openstack
diff --git a/nfvbench/credentials.py b/nfvbench/credentials.py
index 530ad69..b3e4a04 100644
--- a/nfvbench/credentials.py
+++ b/nfvbench/credentials.py
@@ -21,6 +21,8 @@ import getpass
from keystoneauth1.identity import v2
from keystoneauth1.identity import v3
from keystoneauth1 import session
+from keystoneclient import client
+from keystoneclient import utils
from log import LOG
@@ -106,6 +108,7 @@ class Credentials(object):
self.rc_project_domain_name = None
self.rc_project_name = None
self.rc_identity_api_version = 2
+ self.is_admin = False
success = True
if openrc_file:
@@ -164,3 +167,15 @@ class Credentials(object):
'Please enter your OpenStack Password: ')
if not self.rc_password:
self.rc_password = ""
+
+ # check if user has admin role in OpenStack project
+ try:
+ keystone = client.Client(session=self.get_session())
+ user = utils.find_resource(keystone.users, self.rc_username)
+ project = utils.find_resource(keystone.projects, self.rc_project_name)
+ roles = keystone.roles.list(user=user.id, project=project.id)
+ for role in roles:
+ if role.name == 'admin':
+ self.is_admin = True
+ except Exception:
+ LOG.warning("User is not admin, no permission to list user roles")
diff --git a/test/test_chains.py b/test/test_chains.py
index ebc606e..812aece 100644
--- a/test/test_chains.py
+++ b/test/test_chains.py
@@ -22,6 +22,7 @@ from mock import patch
import pytest
from nfvbench.chain_runner import ChainRunner
+from nfvbench.chaining import ChainException
from nfvbench.chaining import ChainVnfPort
from nfvbench.chaining import InstancePlacer
from nfvbench.compute import Compute
@@ -119,18 +120,87 @@ def _test_pvp_chain(config, cred, mock_glance, mock_neutron, mock_client):
openstack_spec = OpenStackSpec()
specs.set_openstack_spec(openstack_spec)
cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = True
runner = ChainRunner(config, cred, specs, BasicFactory())
runner.close()
def test_pvp_chain_runner():
"""Test PVP chain runner."""
cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = True
for shared_net in [True, False]:
for sc in [ChainType.PVP]:
for scc in [1, 2]:
config = _get_chain_config(sc, scc, shared_net)
_test_pvp_chain(config, cred)
+
+# Test not admin exception with empty value is raised
+@patch.object(Compute, 'find_image', _mock_find_image)
+@patch('nfvbench.chaining.Client')
+@patch('nfvbench.chaining.neutronclient')
+@patch('nfvbench.chaining.glanceclient')
+def _test_pvp_chain_no_admin_no_config_values(config, cred, mock_glance, mock_neutron, mock_client):
+ # instance = self.novaclient.servers.create(name=vmname,...)
+ # instance.status == 'ACTIVE'
+ mock_client.return_value.servers.create.return_value.status = 'ACTIVE'
+ netw = {'id': 0, 'provider:network_type': 'vlan', 'provider:segmentation_id': 1000}
+ mock_neutron.Client.return_value.create_network.return_value = {'network': netw}
+ mock_neutron.Client.return_value.list_networks.return_value = {'networks': None}
+ specs = Specs()
+ openstack_spec = OpenStackSpec()
+ specs.set_openstack_spec(openstack_spec)
+ runner = ChainRunner(config, cred, specs, BasicFactory())
+ runner.close()
+
+def test_pvp_chain_runner_no_admin_no_config_values():
+ """Test PVP chain runner."""
+ cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = False
+ for shared_net in [True, False]:
+ for sc in [ChainType.PVP]:
+ for scc in [1, 2]:
+ config = _get_chain_config(sc, scc, shared_net)
+ with pytest.raises(ChainException):
+ _test_pvp_chain_no_admin_no_config_values(config, cred)
+
+# Test not admin with mandatory parameters values in config file
+@patch.object(Compute, 'find_image', _mock_find_image)
+@patch('nfvbench.chaining.Client')
+@patch('nfvbench.chaining.neutronclient')
+@patch('nfvbench.chaining.glanceclient')
+def _test_pvp_chain_no_admin_config_values(config, cred, mock_glance, mock_neutron, mock_client):
+ # instance = self.novaclient.servers.create(name=vmname,...)
+ # instance.status == 'ACTIVE'
+ mock_client.return_value.servers.create.return_value.status = 'ACTIVE'
+ netw = {'id': 0, 'provider:network_type': 'vlan', 'provider:segmentation_id': 1000}
+ mock_neutron.Client.return_value.create_network.return_value = {'network': netw}
+ mock_neutron.Client.return_value.list_networks.return_value = {'networks': None}
+ specs = Specs()
+ openstack_spec = OpenStackSpec()
+ specs.set_openstack_spec(openstack_spec)
+ runner = ChainRunner(config, cred, specs, BasicFactory())
+ runner.close()
+
+def test_pvp_chain_runner_no_admin_config_values():
+ """Test PVP chain runner."""
+ cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = False
+ for shared_net in [True, False]:
+ for sc in [ChainType.PVP]:
+ for scc in [1, 2]:
+ config = _get_chain_config(sc, scc, shared_net)
+ config.availability_zone = "az"
+ config.hypervisor_hostname = "server"
+ # these are the 2 valid forms of vlan ranges
+ if scc == 1:
+ config.vlans = [100, 200]
+ else:
+ config.vlans = [[port * 100 + index for index in range(scc)]
+ for port in range(2)]
+ _test_pvp_chain_no_admin_config_values(config, cred)
+
+
@patch.object(Compute, 'find_image', _mock_find_image)
@patch('nfvbench.chaining.Client')
@patch('nfvbench.chaining.neutronclient')
@@ -145,6 +215,7 @@ def _test_ext_chain(config, cred, mock_glance, mock_neutron, mock_client):
openstack_spec = OpenStackSpec()
specs.set_openstack_spec(openstack_spec)
cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = True
runner = ChainRunner(config, cred, specs, BasicFactory())
runner.close()
@@ -155,6 +226,7 @@ def test_ext_chain_runner():
shared/not shared net x arp/no_arp x scc 1 or 2
"""
cred = MagicMock(spec=nfvbench.credentials.Credentials)
+ cred.is_admin = True
for shared_net in [True, False]:
for no_arp in [False, True]:
for scc in [1, 2]: