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:
parent
2f1c734586
commit
b92ea87db5
devstack
gbpservice
neutron/services/servicechain/plugins/ncp/node_drivers
nfp
base_configurator/controllers
lib
orchestrator/modules
proxy_agent/notifications
tests/contrib
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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 = []
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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})
|
||||
|
Loading…
x
Reference in New Issue
Block a user