diff --git a/docker-compose.yml b/docker-compose.yml index 514959f4d784d057d9e7cb89d3694c6be41d68d2..5c8a25fe176996142969ae59b91636a599afec7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: context: . dockerfile: docker-compose/Dockerfile_FOD image: flowspydjango - command: sh -c '/opt/setup_environment.sh && while ! mysqladmin -h db ping; do echo "DB not yet ready, waiting 1 sec"; sleep 1; done && echo "database is ready" && /opt/FOD/pythonenv ./manage.py migrate && exec supervisord -c docker-compose/fod_celery_supervisord.conf' + command: sh -c '/opt/setup_environment.sh && while ! mysqladmin -h db ping; do echo "DB not yet ready, waiting 1 sec"; sleep 1; done && echo "database is ready" && /opt/FOD/pythonenv ./manage.py migrate && exec /opt/FOD/pythonenv ./manage.py celery_worker' container_name: celeryfod depends_on: - db diff --git a/docker-compose/.env_fod b/docker-compose/.env_fod index 0b50b88ecc3b4405828e3f595e9384fc12083b67..12143325cc25a6d4ef14abb17d49eaccefa70f85 100644 --- a/docker-compose/.env_fod +++ b/docker-compose/.env_fod @@ -19,3 +19,4 @@ FOD_DB_USER=root FOD_DB_PASS= FOD_DB_HOST=db FOD_DB_PORT= +FOD_EXABGP_NOTIFY=http://exabgp1:5000/ diff --git a/exabgp-remote/Dockerfile b/exabgp-remote/Dockerfile index 21caa0790b5cc1153871b3fca929d3730a31761d..6f1bb37b821c55c4938bc96818b3bd2e4d96ac6d 100644 --- a/exabgp-remote/Dockerfile +++ b/exabgp-remote/Dockerfile @@ -13,7 +13,9 @@ RUN mkdir -p /var/run/supervisor /opt/exabgp WORKDIR /opt/exabgp COPY requirements.txt . RUN pip install -r requirements.txt -RUN mkfifo /opt/exabgp/run/exabgp.{in,out} -RUN chmod 666 /opt/exabgp/run/exabgp.{in,out} +RUN mkfifo /var/run/exabgp.in +RUN mkfifo /var/run/exabgp.out +RUN chmod 666 /var/run/exabgp.in +RUN chmod 666 /var/run/exabgp.out CMD supervisord -c ./fod_exabgp_supervisord.conf diff --git a/flowspec/logging_utils.py b/flowspec/logging_utils.py index aa5828dc890790287b82189709748602accb069c..e4738b6a0f313bd26339b251dafe116aaff07709 100644 --- a/flowspec/logging_utils.py +++ b/flowspec/logging_utils.py @@ -17,7 +17,7 @@ def logger_init_default(logger_name, logfile_basename, test_logging): if hasattr(settings, "LOG_LEVEL"): if settings.LOG_LEVEL == "error": - LOG_LEVEL = logging.ERRORG + LOG_LEVEL = logging.ERROR elif settings.LOG_LEVEL == "warn": LOG_LEVEL = logging.WARN elif settings.LOG_LEVEL == "info": diff --git a/flowspec/tasks.py b/flowspec/tasks.py index cdde0f69cf8bb70892c751a998f5bd0995cc49ba..4c387e1faf03b193c8095fc6479c8ceba4eb5cef 100644 --- a/flowspec/tasks.py +++ b/flowspec/tasks.py @@ -72,6 +72,7 @@ def add(routepk, callback=None): @shared_task(ignore_result=True, autoretry_for=(TimeLimitExceeded, SoftTimeLimitExceeded), retry_backoff=True, retry_kwargs={'max_retries': settings.NETCONF_MAX_RETRY_BEFORE_ERROR}) def edit(routepk, route_original__data, callback=None): + logger.info("tasks::edit(): delayed edit") from flowspec.models import Route route = Route.objects.get(pk=routepk) status_pre = route.status @@ -96,8 +97,10 @@ def edit(routepk, route_original__data, callback=None): #logger.info("tasks::edit(): route_original__object_type="+str(type(route_original__object))+" route_original__object="+str(route_original__object)) #applier = PR.Applier(route_object=route) + logger.info("tasks::edit(): invoking applier") applier = PR.Applier(route_object=route, route_objects_all=Route.objects.all(), route_object_original=route_original__data) commit, response, response_lowlevel = applier.apply(operation="replace") + logger.info(f"tasks::edit(): response from applier {response}") if commit: route.status = "ACTIVE" try: @@ -242,6 +245,7 @@ def batch_delete(routes, **kwargs): @shared_task(ignore_result=True) def announce(messg, user, route): + logger.info("tasks::announce(): delayed announce") route_dict = model_to_dict(route) rule_changelog_logger.info(messg+" route_dict="+str(route_dict)) diff --git a/utils/proxy.py b/utils/proxy.py index 8de6502610b7d0cdea6e1d11c59a62c585fd1044..1574f391ff58d362de012d088706fc9efc863979 100644 --- a/utils/proxy.py +++ b/utils/proxy.py @@ -3,9 +3,18 @@ from django.conf import settings +import flowspec.logging_utils +logger = flowspec.logging_utils.logger_init_default(__name__, "celery_exabpg.log", False) + +logger.info(f"proxy::proxy class is {settings.PROXY_CLASS}") + if not hasattr(settings, "PROXY_CLASS") or settings.PROXY_CLASS == "proxy_netconf_junos": + logger.info("proxy::invoking netconf junos") from utils import proxy_netconf_junos as PR0 elif settings.PROXY_CLASS == "proxy_exabgp": + logger.info("proxy::invoking exabgp") from utils import proxy_exabgp as PR0 - +elif settings.PROXY_CLASS == "proxy_exabgp_remote": + logger.info("proxy::invoking exabgp remote") + from utils import proxy_exabgp_remote as PR0 diff --git a/utils/proxy_exabgp_remote.py b/utils/proxy_exabgp_remote.py new file mode 100644 index 0000000000000000000000000000000000000000..df8fcf31892db3bf4b9a18986c5c3b6545fc43ad --- /dev/null +++ b/utils/proxy_exabgp_remote.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- vim:fileencoding=utf-8: +# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab + +# /srv/venv/lib/python3.11/site-packages/exabgp/application/cli.py +#from exabgp.application.cli import main as exabgp_cli_main + +# utils/exabgpcli.py + +from django.conf import settings +from utils.exabgpcli import exabgp_interaction +import utils.route_spec_utils as route_spec_utils + +from . import jncdevice as np +from ncclient import manager +from ncclient.transport.errors import AuthenticationError, SSHError +from ncclient.operations.rpc import RPCError +from lxml import etree as ET +from django.conf import settings +import logging, os +from django.core.cache import cache +import redis +from celery.exceptions import TimeLimitExceeded, SoftTimeLimitExceeded +from .portrange import parse_portrange +import traceback +from ipaddress import ip_network +from .flowspec_utils import map__ip_proto__for__ip_version__to_flowspec +#import xml.etree.ElementTree as ET +import re +import sys +import requests + +import flowspec.logging_utils +logger = flowspec.logging_utils.logger_init_default(__name__, "celery_exabpg.log", False) + +#print("loading proxy_exabgp", file=sys.stderr) + +cwd = os.getcwd() + +class Applier(object): + def __init__(self, route_objects=[], route_object=None, route_object_original=None, route_objects_all=[]): + logger.info("proxy_exabgp_remote::Applier::__init__") + self.route_object = route_object + self.route_objects = route_objects + self.route_object_original = route_object_original + self.route_objects_all = route_objects_all + + def apply(self, configuration=None, operation=None): + logger.info("proxy_exabgp_remote::apply(): called operation="+str(operation)) + + exapeers = os.getenv('FOD_EXABGP_NOTIFY', '').split(',') + + logger.info(f"proxy_exabgp_remote::apply(): notifying {len(exapeers)} exabgp instances") + + try: + route = self.route_object + route_objects_all = self.route_objects_all + route_original = self.route_object_original + + status = True + + for exa in exapeers: + logger.info(f"proxy_exabgp_remote::apply(): notifying peer {exa}") + + r = requests.get(exa) + if r.status_code == requests.codes.ok: + status = ( status and True ) + else: + status = False + + msg = 'hi' + + if status: + return status, "successfully committed", msg + else: + return status, msg, msg + + except Exception as e: + logger.error("proxy_exabgp_remote::apply(): got exception="+str(e), exc_info=True)