NFP - Fixes to resolve NFP gate failures

Resolved following issues :
1) Added port security extension while configuring neutron for NFP,
2) Corrected polling time calculation in nfp_node_driver,
3) Explicitly making a dhcp request whenever service vm comes up,
4) Corrected svc_management group creation, to use different l3 policy
for gate tests.

Change-Id: I2e88103c174ce864f618c0eb4e0202dcb500a4fa
Closes-Bug: 1663134
This commit is contained in:
ashu_mishra 2017-02-09 12:42:15 +05:30
parent 2f1c734586
commit b92ea87db5
10 changed files with 176 additions and 102 deletions

View File

@ -27,6 +27,7 @@ function gbp_configure_neutron {
}
function nfp_configure_neutron {
NEUTRON_ML2_CONF="/etc/neutron/plugins/ml2/ml2_conf.ini"
iniset $NEUTRON_CONF keystone_authtoken admin_tenant_name "service"
iniset $NEUTRON_CONF keystone_authtoken admin_user "neutron"
iniset $NEUTRON_CONF keystone_authtoken admin_password $ADMIN_PASSWORD
@ -40,6 +41,12 @@ function nfp_configure_neutron {
fi
iniset $NEUTRON_CONF nfp_node_driver is_service_admin_owned "True"
iniset $NEUTRON_CONF nfp_node_driver svc_management_ptg_name "svc_management_ptg"
extn_drivers=$(iniget $NEUTRON_ML2_CONF ml2 extension_drivers)
if [[ -n $extn_drivers ]];then
iniset $NEUTRON_ML2_CONF ml2 extension_drivers $extn_drivers,port_security
else
iniset $NEUTRON_ML2_CONF ml2 extension_drivers port_security
fi
}
function configure_nfp_loadbalancer {

View File

@ -14,6 +14,7 @@
import eventlet
from eventlet import greenpool
import threading
import time
from keystoneclient import exceptions as k_exceptions
from keystoneclient.v2_0 import client as keyclient
@ -467,7 +468,8 @@ class NFPNodeDriver(driver_base.NodeDriverBase):
network_function_id,
operation):
# Check for NF status in a separate thread
LOG.debug("Spawning thread for nf ACTIVE poll")
LOG.debug("Spawning thread for nf ACTIVE poll operation: %s" % (
operation))
nfp_context = NFPContext.get_nfp_context(context.instance['id'])
if operation == nfp_constants.DELETE:
gth = nfp_context['thread_pool'].spawn(
@ -685,18 +687,28 @@ class NFPNodeDriver(driver_base.NodeDriverBase):
network_function_id):
time_waited = 0
network_function = None
while time_waited < cfg.CONF.nfp_node_driver.service_delete_timeout:
curr_time = start_time = int(time.time())
timeout = cfg.CONF.nfp_node_driver.service_delete_timeout
while curr_time - start_time < timeout:
curr_time = int(time.time())
network_function = self.nfp_notifier.get_network_function(
context.plugin_context, network_function_id)
if network_function:
LOG.debug("Got %s nf result for NF: %s with status:%s,"
"time waited: %s" % (network_function_id, 'delete',
time_waited, network_function['status']))
if not network_function:
break
eventlet.sleep(5)
time_waited = time_waited + 5
LOG.debug("Deleting sci nf mapping")
self._delete_node_instance_network_function_map(
context.plugin_session,
context.current_node['id'],
context.instance['id'])
LOG.debug("sci nf mapping got deleted. NF got deldted.")
if network_function:
LOG.error(_LE("Delete network function %(network_function)s "
@ -710,9 +722,15 @@ class NFPNodeDriver(driver_base.NodeDriverBase):
time_waited = 0
network_function = None
timeout = cfg.CONF.nfp_node_driver.service_create_timeout
while time_waited < timeout:
curr_time = start_time = int(time.time())
while curr_time - start_time < timeout:
curr_time = int(time.time())
network_function = self.nfp_notifier.get_network_function(
context.plugin_context, network_function_id)
LOG.debug("Got %s nf result for NF: %s with status:%s,"
"time waited: %s" % (network_function_id, operation,
time_waited, network_function['status']))
if not network_function:
LOG.error(_LE("Failed to retrieve network function"))
eventlet.sleep(5)

View File

@ -16,6 +16,7 @@ from oslo_log import log as logging
import pecan
import requests
import subprocess
from subprocess import CalledProcessError
import time
from gbpservice.nfp.pecan import base_controller
@ -74,12 +75,19 @@ class Controller(base_controller.BaseController):
def _verify_vm_reachability(self, vm_ip, vm_port):
reachable = False
command = 'nc ' + vm_ip + ' ' + vm_port + ' -z'
ping_command = 'ping -c1 ' + vm_ip
for _ in range(self.max_retries):
try:
subprocess.check_output(ping_command, stderr=subprocess.STDOUT,
shell=True)
subprocess.check_output(command, stderr=subprocess.STDOUT,
shell=True)
reachable = True
break
except CalledProcessError as err:
msg = ("Exception: %s " % err)
LOG.error(msg)
time.sleep(5)
except Exception:
time.sleep(5)
return reachable
@ -158,9 +166,11 @@ class Controller(base_controller.BaseController):
resource = config_data['resource']
operation = context['operation']
msg1 = ("Request recieved :: %s" % body)
LOG.info(msg1)
if 'device_ip' in context:
msg = ("POSTING DATA TO VM :: %s" % body)
LOG.info(msg)
msg3 = ("POSTING DATA TO VM :: %s" % body)
LOG.info(msg3)
device_ip = context['device_ip']
ip = str(device_ip)
resource_id = (context['nfp_context']['nfp_context']['id']
@ -168,12 +178,17 @@ class Controller(base_controller.BaseController):
context['nfp_context'].get('nfp_context') else '')
if operation == 'delete' and resource_id == 'PERFORM_CLEAR_HM':
return
msg5 = ("Verifying vm reachability on ip: %s, port: %s" % (
ip, self.vm_port))
LOG.info(msg5)
is_vm_reachable = self._verify_vm_reachability(ip,
self.vm_port)
if is_vm_reachable:
requests.post(
'http://' + ip + ':' + self.vm_port + '/v1/nfp/' +
self.method_name, data=jsonutils.dumps(body))
msg4 = ("requests successfull for data: %s" % body)
LOG.info(msg4)
else:
raise Exception('VM is not reachable')
cache_ips.add(device_ip)

View File

@ -283,14 +283,12 @@ def get_response_from_configurator(conf):
message = ("get_notification ->"
"GET request failed. Reason : %s" % (rce))
LOG.error(message)
return "get_notification -> GET request failed. Reason : %s" % (
rce)
return []
except Exception as e:
message = ("get_notification ->"
"GET request failed. Reason : %s" % (e))
LOG.error(message)
return "get_notification -> GET request failed. Reason : %s" % (
e)
return []
elif conf.backend == UNIX_REST:
try:
@ -306,15 +304,13 @@ def get_response_from_configurator(conf):
"GET request failed. Reason : %s" % (
rce))
LOG.error(message)
return "get_notification -> GET request failed. Reason : %s" % (
rce)
return []
except Exception as e:
message = ("get_notification ->"
"GET request failed. Reason : %s" % (
e))
LOG.error(message)
return "get_notification -> GET request failed. Reason : %s" % (
e)
return []
else:
rpc_cbs_data = []

View File

@ -146,56 +146,59 @@ class RpcHandler(object):
# RPC APIs status notification from Configurator
def network_function_notification(self, context, notification_data):
info = notification_data.get('info')
responses = notification_data.get('notification')
request_info = info.get('context')
operation = request_info.get('operation')
logging_context = request_info.get('logging_context')
nfp_logging.store_logging_context(**logging_context)
try:
info = notification_data.get('info')
responses = notification_data.get('notification')
request_info = info.get('context')
operation = request_info.get('operation')
logging_context = request_info.get('logging_context')
nfp_logging.store_logging_context(**logging_context)
for response in responses:
resource = response.get('resource')
data = response.get('data')
result = data.get('status_code')
if resource not in [nfp_constants.HEALTHMONITOR_RESOURCE,
nfp_constants.PERIODIC_HM]:
resource = nfp_constants.GENERIC_CONFIG
for response in responses:
resource = response.get('resource')
data = response.get('data')
result = data.get('status_code')
if resource not in [nfp_constants.HEALTHMONITOR_RESOURCE,
nfp_constants.PERIODIC_HM]:
resource = nfp_constants.GENERIC_CONFIG
is_delete_request = True if operation == 'delete' else False
is_delete_request = True if operation == 'delete' else False
if resource == nfp_constants.PERIODIC_HM:
event_id = self.handle_periodic_hm_resource(result)
break
if resource == nfp_constants.PERIODIC_HM:
event_id = self.handle_periodic_hm_resource(result)
break
if is_delete_request:
event_id = self.rpc_event_mapping[resource][1]
else:
event_id = self.rpc_event_mapping[resource][0]
if result.lower() != 'success':
LOG.info(_LI("RPC Handler response data:%(data)s"),
{'data': data})
if is_delete_request:
# Ignore any deletion errors, generate SUCCESS event
event_id = self.rpc_event_mapping[resource][1]
else:
event_id = self.rpc_event_mapping[resource][2]
break
event_id = self.rpc_event_mapping[resource][0]
nf_id = request_info.pop('nf_id')
nfi_id = request_info.pop('nfi_id')
nfd_id = request_info.pop('nfd_id')
request_info['network_function_id'] = nf_id
request_info['network_function_instance_id'] = nfi_id
request_info['network_function_device_id'] = nfd_id
event_data = request_info
event_data['id'] = request_info['network_function_device_id']
if result.lower() != 'success':
LOG.info(_LI("RPC Handler response data:%(data)s"),
{'data': data})
if is_delete_request:
# Ignore any deletion errors, generate SUCCESS event
event_id = self.rpc_event_mapping[resource][1]
else:
event_id = self.rpc_event_mapping[resource][2]
break
key = nf_id
self._create_event(event_id=event_id,
event_data=event_data,
key=key)
nfp_logging.clear_logging_context()
nf_id = request_info.pop('nf_id')
nfi_id = request_info.pop('nfi_id')
nfd_id = request_info.pop('nfd_id')
request_info['network_function_id'] = nf_id
request_info['network_function_instance_id'] = nfi_id
request_info['network_function_device_id'] = nfd_id
event_data = request_info
event_data['id'] = request_info['network_function_device_id']
key = nf_id
self._create_event(event_id=event_id,
event_data=event_data,
key=key)
nfp_logging.clear_logging_context()
except Exception as err:
LOG.error(_LE("Exception: in RPC handler: %(err)s"), {'err': err})
class DeviceOrchestrator(nfp_api.NfpEventHandler):

View File

@ -132,7 +132,8 @@ class RpcHandler(object):
'''Invoked in an RPC Call. Return the Network function DB object'''
LOG.debug("Received RPC call for GET NETWORK FUNCTION for NFI %s"
% network_function_id)
service_orchestrator = ServiceOrchestrator(self._controller, self.conf)
service_orchestrator = ServiceOrchestrator(self._controller,
self.conf)
return service_orchestrator.get_network_function(
context, network_function_id)
@ -350,55 +351,59 @@ class RpcHandlerConfigurator(object):
@log_helpers.log_method_call
def network_function_notification(self, context, notification_data):
info = notification_data.get('info')
responses = notification_data.get('notification')
request_info = info.get('context')
operation = request_info.get('operation')
logging_context = request_info.get('logging_context')
nfp_logging.store_logging_context(**logging_context)
serialize = False
try:
info = notification_data.get('info')
responses = notification_data.get('notification')
request_info = info.get('context')
operation = request_info.get('operation')
logging_context = request_info.get('logging_context')
nfp_logging.store_logging_context(**logging_context)
serialize = False
for response in responses:
resource = response.get('resource')
data = response.get('data')
result = data.get('status_code')
for response in responses:
resource = response.get('resource')
data = response.get('data')
result = data.get('status_code')
if result.lower() != 'success':
if operation == 'create':
event_id = self.rpc_event_mapping[resource][0]
elif operation == 'delete':
return
elif operation == 'update':
serialize = True
event_id = self.rpc_event_mapping[resource][2]
elif operation == 'pt_add':
serialize = True
event_id = self.rpc_event_mapping[resource][3]
elif operation == 'pt_remove':
serialize = True
event_id = self.rpc_event_mapping[resource][4]
elif operation == 'consumer_add':
serialize = True
event_id = self.rpc_event_mapping[resource][5]
if result.lower() != 'success':
if operation == 'create':
event_id = self.rpc_event_mapping[resource][0]
elif operation == 'delete':
return
elif operation == 'update':
serialize = True
event_id = self.rpc_event_mapping[resource][2]
elif operation == 'pt_add':
serialize = True
event_id = self.rpc_event_mapping[resource][3]
elif operation == 'pt_remove':
serialize = True
event_id = self.rpc_event_mapping[resource][4]
elif operation == 'consumer_add':
serialize = True
event_id = self.rpc_event_mapping[resource][5]
else:
serialize = True
event_id = self.rpc_event_mapping[resource][6]
break
else:
serialize = True
event_id = self.rpc_event_mapping[resource][6]
break
else:
if operation == 'delete':
event_id = 'USER_CONFIG_DELETED'
else:
event_id = 'CONFIG_APPLIED'
nf_id = request_info.pop('nf_id')
nfi_id = request_info.pop('nfi_id')
nfd_id = request_info.pop('nfd_id')
request_info['network_function_id'] = nf_id
request_info['network_function_instance_id'] = nfi_id
request_info['network_function_device_id'] = nfd_id
event_data = request_info
self._create_event(event_id=event_id,
event_data=event_data, serialize=serialize)
nfp_logging.clear_logging_context()
if operation == 'delete':
event_id = 'USER_CONFIG_DELETED'
else:
event_id = 'CONFIG_APPLIED'
nf_id = request_info.pop('nf_id')
nfi_id = request_info.pop('nfi_id')
nfd_id = request_info.pop('nfd_id')
request_info['network_function_id'] = nf_id
request_info['network_function_instance_id'] = nfi_id
request_info['network_function_device_id'] = nfd_id
event_data = request_info
self._create_event(event_id=event_id,
event_data=event_data, serialize=serialize)
nfp_logging.clear_logging_context()
except Exception as err:
LOG.error(_LE("Exception in NSO RPC Reciever: %(err)s"),
{'err': err})
class ServiceOrchestrator(nfp_api.NfpEventHandler):

View File

@ -58,6 +58,8 @@ class PullNotification(nfp_api.NfpEventHandler):
'network_function_notification',
notification_data=notification)
except Exception as e:
msg = "Exception while calling notification: %s" % (e)
LOG.error(msg)
raise Exception(e)
@nfp_api.poll_event_desc(event='PULL_NOTIFICATIONS',

View File

@ -115,3 +115,7 @@ quota_security_group = -1
quota_security_group_rule = -1
quota_router = -1
quota_floatingip = -1
[[post-config|/etc/neutron/plugins/ml2/ml2_conf.ini]]
[ml2]
extension_drivers = port_security

View File

@ -150,7 +150,13 @@ function create_nfp_gbp_resources {
gbp service-profile-create --servicetype LOADBALANCER --insertion-mode l3 --shared True --service-flavor service_vendor=haproxy,device_type=None --vendor NFP base_mode_lb
gbp service-profile-create --servicetype FIREWALL --insertion-mode l3 --shared True --service-flavor service_vendor=vyos,device_type=None --vendor NFP base_mode_fw
gbp service-profile-create --servicetype FIREWALL --insertion-mode l3 --shared True --service-flavor service_vendor=nfp,device_type=nova,image_name=$IMAGE_NAME_FLAT,flavor=$FLAVOR --vendor NFP base_mode_fw_vm
gbp group-create svc_management_ptg --service_management True
gbp l3policy-create --ip-version 4 --ip-pool 172.16.0.0/16 --subnet-prefix-length 20 --proxy-ip-pool=172.17.0.0/16 service_management
gbp l2policy-create --l3-policy service_management svc_management_ptg
gbp group-create svc_management_ptg --service_management True --l2-policy svc_management_ptg
}
function delete_nfp_gbp_resources {

View File

@ -46,6 +46,15 @@ class Controller(rest.RestController):
try:
self.method_name = "network_function_device_notification"
super(Controller, self).__init__()
ip_a = subprocess.Popen('ifconfig -a', shell=True,
stdout=subprocess.PIPE).stdout.read()
out1 = subprocess.Popen('dhclient eth0', shell=True,
stdout=subprocess.PIPE).stdout.read()
out2 = subprocess.Popen('dhclient eth0', shell=True,
stdout=subprocess.PIPE).stdout.read()
output = "%s\n%s\n%s" % (ip_a, out1, out2)
LOG.info(_LI("Dhclient on eth0, result: %(output)s") %
{'output': output})
except Exception as err:
msg = (
"Failed to initialize Controller class %s." %
@ -156,6 +165,15 @@ class Controller(rest.RestController):
{'healthmonitor_data': config_data})
def _configure_interfaces(self, config_data):
out1 = subprocess.Popen('sudo dhclient eth1', shell=True,
stdout=subprocess.PIPE).stdout.read()
out2 = subprocess.Popen('sudo dhclient eth2', shell=True,
stdout=subprocess.PIPE).stdout.read()
out3 = subprocess.Popen('cat /etc/network/interfaces', shell=True,
stdout=subprocess.PIPE).stdout.read()
output = "%s\n%s\n%s" % (out1, out2, out3)
LOG.info(_LI("Dhclient on eth0, result: %(initial_data)s") %
{'initial_data': output})
LOG.info(_LI("Configures interfaces with configuration "
"data : %(interface_data)s ") %
{'interface_data': config_data})