Skip to content
Snippets Groups Projects
Commit b278bce7 authored by Pelle Koster's avatar Pelle Koster
Browse files

Use error report inventory endpoint for error report

parent f0ab904e
Branches
Tags
No related merge requests found
...@@ -47,7 +47,10 @@ import pathlib ...@@ -47,7 +47,10 @@ import pathlib
import sys import sys
from typing import Sequence, Tuple from typing import Sequence, Tuple
from brian_polling_manager.influx import influx_client from brian_polling_manager.influx import influx_client
from brian_polling_manager.inventory import load_interfaces from brian_polling_manager.inventory import (
INVENTORY_INTERFACES_SCHEMA,
load_inventory_json,
)
import click import click
from influxdb import InfluxDBClient from influxdb import InfluxDBClient
from brian_polling_manager.error_report.config import load from brian_polling_manager.error_report.config import load
...@@ -59,6 +62,7 @@ from brian_polling_manager.error_report.report import ( ...@@ -59,6 +62,7 @@ from brian_polling_manager.error_report.report import (
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
DEFAULT_INTERFACES_URL = "/poller/error-report-interfaces"
# The error field names in the influx query vs their reporting name # The error field names in the influx query vs their reporting name
ERROR_FIELDS = { ERROR_FIELDS = {
...@@ -303,35 +307,20 @@ def is_excluded_interface(ifc, exclusions: Sequence[Tuple[str, str]]): ...@@ -303,35 +307,20 @@ def is_excluded_interface(ifc, exclusions: Sequence[Tuple[str, str]]):
) )
def get_relevant_interfaces(hosts): def get_relevant_interfaces(config):
"""Get interface info from inventory provider. Some interfaces are considered """Get interface info from inventory provider. Some interfaces are considered
irrelevant based on their description irrelevant based on their description
""" """
return _filter_and_sort_interfaces(load_interfaces(hosts)) url = config.get("inventory-url") or DEFAULT_INTERFACES_URL
return _sort_interfaces(
load_inventory_json(url, config["inventory"], INVENTORY_INTERFACES_SCHEMA)
def _filter_and_sort_interfaces(interfaces):
# We may want to put this logic inside inventory provider and serve from a new
# endpoint
return dict(
sorted(
((i["router"], i["name"]), i)
for i in interfaces
if all(
(
"PHY" in i["description"].upper(),
"SPARE" not in i["description"].upper(),
"NON-OPERATIONAL" not in i["description"].upper(),
"RESERVED" not in i["description"].upper(),
"TEST" not in i["description"].upper(),
"dsc." not in i["name"].lower(),
"fxp" not in i["name"].lower(),
)
)
)
) )
def _sort_interfaces(interfaces):
return dict(sorted(((i["router"], i["name"]), i) for i in interfaces))
def main(config: dict, send_mail: bool): def main(config: dict, send_mail: bool):
"""Main function for the error reporting script """Main function for the error reporting script
...@@ -339,7 +328,7 @@ def main(config: dict, send_mail: bool): ...@@ -339,7 +328,7 @@ def main(config: dict, send_mail: bool):
""" """
logger.info(f"Retrieving interfaces from inventory provider: {config['inventory']}") logger.info(f"Retrieving interfaces from inventory provider: {config['inventory']}")
all_interfaces = get_relevant_interfaces(config["inventory"]) all_interfaces = get_relevant_interfaces(config)
client = influx_client(config["influx"]) client = influx_client(config["influx"])
with client: with client:
logger.info("Retrieving error points from influxdb...") logger.info("Retrieving error points from influxdb...")
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
"starttls": false "starttls": false
}, },
"inventory": ["blah"], "inventory": ["blah"],
"inventory-url": "/poller/interfaces",
"influx": { "influx": {
"hostname": "hostname", "hostname": "hostname",
"database": "dbname", "database": "dbname",
......
...@@ -36,7 +36,8 @@ def render_email( ...@@ -36,7 +36,8 @@ def render_email(
message["To"] = "; ".join(email_config["to"]) message["To"] = "; ".join(email_config["to"])
if email_config.get("cc"): if email_config.get("cc"):
message["Cc"] = "; ".join(email_config["cc"]) message["Cc"] = "; ".join(email_config["cc"])
if email_config.get("reply_to"):
message["Reply-To"] = email_config["reply_to"]
message["Subject"] = subject message["Subject"] = subject
message.attach(MIMEText(body, "plain")) message.attach(MIMEText(body, "plain"))
......
...@@ -31,22 +31,6 @@ ...@@ -31,22 +31,6 @@
], ],
"snmp-index": 1006 "snmp-index": 1006
}, },
{
"router": "mx1.fra.de.geant.net",
"name": "ae99.1",
"bundle": [],
"bundle-parents": [],
"description": "SRV blah blah bar",
"circuits": [
{
"id": 50028,
"name": "something",
"type": "SERVICE",
"status": "operational"
}
],
"snmp-index": 9999
},
{ {
"router": "rt0.ams.nl.geant.net", "router": "rt0.ams.nl.geant.net",
"name": "lag-1", "name": "lag-1",
......
...@@ -19,9 +19,8 @@ from brian_polling_manager.error_report.cli import ( ...@@ -19,9 +19,8 @@ from brian_polling_manager.error_report.cli import (
INFLUX_TIME_WINDOW_YESTERDAY, INFLUX_TIME_WINDOW_YESTERDAY,
PROCESSED_ERROR_COUNTERS_SCHEMA, PROCESSED_ERROR_COUNTERS_SCHEMA,
MessageCountingLogHandler, MessageCountingLogHandler,
_filter_and_sort_interfaces, _sort_interfaces,
get_error_points, get_error_points,
get_relevant_interfaces,
interface_errors, interface_errors,
is_excluded_interface, is_excluded_interface,
select_error_fields, select_error_fields,
...@@ -32,11 +31,6 @@ from click.testing import CliRunner ...@@ -32,11 +31,6 @@ from click.testing import CliRunner
DATA_DIR = pathlib.Path(__file__).parent / "data" DATA_DIR = pathlib.Path(__file__).parent / "data"
@pytest.fixture(scope="session")
def full_inventory():
return json.loads(((DATA_DIR / "full-inventory.json").read_text()))
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def small_inventory(): def small_inventory():
return json.loads(((DATA_DIR / "small-inventory.json").read_text())) return json.loads(((DATA_DIR / "small-inventory.json").read_text()))
...@@ -123,7 +117,7 @@ def create_error_point(mock_influx_client): ...@@ -123,7 +117,7 @@ def create_error_point(mock_influx_client):
@pytest.fixture @pytest.fixture
def get_interface_errors(small_inventory, mock_influx_client): def get_interface_errors(small_inventory, mock_influx_client):
interfaces = _filter_and_sort_interfaces(small_inventory) interfaces = _sort_interfaces(small_inventory)
def _get_interface_errors(**kwargs): def _get_interface_errors(**kwargs):
defaults = { defaults = {
...@@ -188,23 +182,6 @@ def test_validate_config(tmp_path): ...@@ -188,23 +182,6 @@ def test_validate_config(tmp_path):
} }
def test_get_relevant_interfaces(full_inventory):
with patch.object(cli, "load_interfaces", return_value=full_inventory) as mock:
result = get_relevant_interfaces("some-host")
assert mock.call_args == call("some-host")
assert 0 < len(result) < len(full_inventory)
assert all(
"PHY" in i["description"].upper()
and "SPARE" not in i["description"].upper()
and "NON-OPERATIONAL" not in i["description"].upper()
and "RESERVED" not in i["description"].upper()
and "TEST" not in i["description"].upper()
and "dsc." not in i["name"].lower()
and "fxp" not in i["name"].lower()
for i in result.values()
)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"router, interface, exclusions, is_excluded", "router, interface, exclusions, is_excluded",
[ [
...@@ -552,6 +529,18 @@ def test_render_email_for_multiple_recipients(): ...@@ -552,6 +529,18 @@ def test_render_email_for_multiple_recipients():
assert "Cc: cc1@geant.org; cc2@geant.org" in result assert "Cc: cc1@geant.org; cc2@geant.org" in result
def test_render_email_with_reply_to():
body = "<SOME_BODY>"
config = {
"from": "someone@geant.org",
"to": ["someone.else@geant.org"],
"reply_to": "replyto@geant.org",
}
result = render_email(config, html=body, subject="<subject>")
assert "Reply-To: replyto@geant.org" in result
@patch.object(smtplib, "SMTP") @patch.object(smtplib, "SMTP")
def test_send_email(SMTP): def test_send_email(SMTP):
config = { config = {
...@@ -667,7 +656,7 @@ def test_e2e( ...@@ -667,7 +656,7 @@ def test_e2e(
): ):
create_error_point("mx1.ams.nl.geant.net", "ae1", "today", input_drops=1) create_error_point("mx1.ams.nl.geant.net", "ae1", "today", input_drops=1)
with patch.object( with patch.object(
cli, "load_interfaces", return_value=small_inventory cli, "load_inventory_json", return_value=small_inventory
), patch.object(cli, "influx_client", return_value=mock_influx_client): ), patch.object(cli, "influx_client", return_value=mock_influx_client):
runner = CliRunner() runner = CliRunner()
result = runner.invoke(cli.cli, ["--config", str(config_file)]) result = runner.invoke(cli.cli, ["--config", str(config_file)])
...@@ -691,7 +680,7 @@ def test_e2e( ...@@ -691,7 +680,7 @@ def test_e2e(
@patch.object(cli, "setup_logging", return_value=MessageCountingLogHandler()) @patch.object(cli, "setup_logging", return_value=MessageCountingLogHandler())
@patch.object(cli, "main") @patch.object(cli, "main")
def test_e2e_with_errors( def test_e2e_with_errors(
unused_mainmain, unused_main,
setup_logging, setup_logging,
config_file, config_file,
): ):
......
...@@ -12,8 +12,10 @@ from brian_polling_manager.main import REFRESH_RESULT_SCHEMA ...@@ -12,8 +12,10 @@ from brian_polling_manager.main import REFRESH_RESULT_SCHEMA
@pytest.fixture @pytest.fixture
def client(config_filename, mocked_sensu, mocked_inventory): def client(config_filename, mocked_sensu, mocked_inventory):
os.environ['CONFIG_FILENAME'] = config_filename os.environ["CONFIG_FILENAME"] = config_filename
with brian_polling_manager.create_app().test_client() as c: app = brian_polling_manager.create_app()
app.testing = True
with app.test_client() as c:
yield c yield c
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment