From eff36daec9bc492542f79f3ec192f5d2876d8db1 Mon Sep 17 00:00:00 2001
From: Remco Tukker <remco.tukker@geant.org>
Date: Fri, 22 Sep 2023 17:27:07 +0200
Subject: [PATCH 1/3] last db publish model as the data in the excel turned out
 to be insufficient

---
 .../survey_publisher_old_db_2022.py           | 35 ++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/compendium_v2/publishers/survey_publisher_old_db_2022.py b/compendium_v2/publishers/survey_publisher_old_db_2022.py
index 5c72d1c5..b6ceea90 100644
--- a/compendium_v2/publishers/survey_publisher_old_db_2022.py
+++ b/compendium_v2/publishers/survey_publisher_old_db_2022.py
@@ -1167,6 +1167,38 @@ def transfer_network_automation(nren_dict):
     db.session.commit()
 
 
+def transfer_network_function_virtualisation(nren_dict):
+    rows = recursive_query(16754)
+    types = recursive_query(16755)
+    types = {(nren_name, year): json.loads(answer) for answer_id, nren_name, year, answer in types}
+    types_comment = recursive_query(16756)
+    types_comment = {(nren_name, year): answer.strip('" ') for answer_id, nren_name, year, answer in types_comment}
+
+    for answer_id, nren_name, year, answer in rows:
+        if nren_name not in nren_dict:
+            logger.warning(f'{nren_name} unknown. Skipping.')
+            continue
+
+        nfv = YesNoPlanned[answer.strip('"').lower()]
+        specifics = types.get((nren_name, year), [])
+        specifics = [s for s in specifics if s]
+        comment = types_comment.get((nren_name, year), "").replace("-", "")
+        if comment:
+            specifics.append(comment)
+            if "Other" in specifics:
+                specifics.remove("Other")
+
+        new_entry = presentation_models.NetworkFunctionVirtualisation(
+            nren=nren_dict[nren_name],
+            nren_id=nren_dict[nren_name].id,
+            year=year,
+            nfv=nfv,
+            nfv_specifics=specifics
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
 def _cli(app):
     with app.app_context():
         nren_dict = helpers.get_uppercase_nren_dict()
@@ -1200,7 +1232,8 @@ def _cli(app):
         transfer_pert_team(nren_dict)
         transfer_alien_wave(nren_dict)
         transfer_external_connections(nren_dict)
-        # traffic ratio was freeform text
+        # traffic ratio was freeform text so we don't transfer it
+        transfer_network_function_virtualisation(nren_dict)
         transfer_network_automation(nren_dict)
 
 
-- 
GitLab


From cac86203220caef9cc156225b38e0a0c21768875 Mon Sep 17 00:00:00 2001
From: Remco Tukker <remco.tukker@geant.org>
Date: Fri, 22 Sep 2023 20:25:19 +0200
Subject: [PATCH 2/3] and one more old db publisher due to incomplete excel
 data

---
 .../survey_publisher_old_db_2022.py           | 34 +++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/compendium_v2/publishers/survey_publisher_old_db_2022.py b/compendium_v2/publishers/survey_publisher_old_db_2022.py
index b6ceea90..2719fbf5 100644
--- a/compendium_v2/publishers/survey_publisher_old_db_2022.py
+++ b/compendium_v2/publishers/survey_publisher_old_db_2022.py
@@ -1199,6 +1199,39 @@ def transfer_network_function_virtualisation(nren_dict):
     db.session.commit()
 
 
+def transfer_monitoring_tools(nren_dict):
+    tools = recursive_query(16672)
+    tools = {(nren_name, year): json.loads(answer) for answer_id, nren_name, year, answer in tools}
+    tools_comment = recursive_query(16673)
+    tools_comment = {(nren_name, year): answer.strip('" ') for answer_id, nren_name, year, answer in tools_comment}
+    netflow = recursive_query(16674)
+    netflow = {(nren_name, year): answer.strip('" ') for answer_id, nren_name, year, answer in netflow}
+
+    for nren_name, year in tools.keys() | tools_comment.keys() | netflow.keys():
+        if nren_name not in nren_dict:
+            logger.warning(f'{nren_name} unknown. Skipping.')
+            continue
+
+        tool_descriptions = tools.get((nren_name, year), [])
+        comment = tools_comment.get((nren_name, year), "").replace("-", "")
+        if comment:
+            tool_descriptions.append(comment)
+            if "Other" in tool_descriptions:
+                tool_descriptions.remove("Other")
+            if "Other " in tool_descriptions:
+                tool_descriptions.remove("Other ")
+
+        new_entry = presentation_models.MonitoringTools(
+            nren=nren_dict[nren_name],
+            nren_id=nren_dict[nren_name].id,
+            year=year,
+            tool_descriptions=tool_descriptions,
+            netflow_processing_description=netflow.get((nren_name, year), "")
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
 def _cli(app):
     with app.app_context():
         nren_dict = helpers.get_uppercase_nren_dict()
@@ -1225,6 +1258,7 @@ def _cli(app):
 
         transfer_fibre_light(nren_dict)
         transfer_network_map_urls(nren_dict)
+        transfer_monitoring_tools(nren_dict)
         transfer_traffic_statistics(nren_dict)
         transfer_siem_vendors(nren_dict)
         transfer_certificate_providers(nren_dict)
-- 
GitLab


From e4936163dce0ccadd17ede113acf6a03da4385b1 Mon Sep 17 00:00:00 2001
From: Remco Tukker <remco.tukker@geant.org>
Date: Fri, 22 Sep 2023 22:04:38 +0200
Subject: [PATCH 3/3] publishing the network excel file

---
 compendium_v2/publishers/excel_parser.py      | 239 +++++++++++++++++-
 compendium_v2/publishers/helpers.py           |   1 +
 .../survey_publisher_legacy_excel.py          | 130 +++++++++-
 test/test_survey_publisher_legacy_excel.py    |   3 +-
 test/test_survey_publisher_old_db_2022.py     |   2 +-
 5 files changed, 370 insertions(+), 5 deletions(-)

diff --git a/compendium_v2/publishers/excel_parser.py b/compendium_v2/publishers/excel_parser.py
index b2d5a3c8..a08ea4bd 100644
--- a/compendium_v2/publishers/excel_parser.py
+++ b/compendium_v2/publishers/excel_parser.py
@@ -3,7 +3,8 @@ import logging
 import openpyxl
 
 from compendium_v2.conversion import mapping
-from compendium_v2.db.presentation_model_enums import CarryMechanism, ConnectivityCoverage, UserCategory, FeeType
+from compendium_v2.db.presentation_model_enums import CarryMechanism, ConnectivityCoverage, MonitoringMethod, \
+    UserCategory, FeeType, YesNoPlanned
 from compendium_v2.environment import setup_logging
 from compendium_v2.resources import get_resource_file_path
 
@@ -827,3 +828,239 @@ def fetch_remote_campuses_excel_data():
     yield from create_points_for_year(2020, 16)
     yield from create_points_for_year(2021, 10)
     yield from create_points_for_year(2022, 4)
+
+
+def fetch_dark_fibre_iru_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Dark Fibre"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+
+    def parse_int(excel_value):
+        if excel_value is None or excel_value == "":
+            return None
+        return int(str(excel_value).replace("-", "").replace(" ", "").replace(".", ""))
+
+    def create_points_for_year(year, start_column):
+        for i in range(10, 53):
+            nren_name = rows[i][start_column].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            s = start_column
+            iru = ""
+            if year > 2019:
+                s += 1
+                iru = rows[i][s].value
+            elif parse_int(rows[i][s + 1].value) is not None:
+                iru = "Yes" if parse_int(rows[i][s + 1].value) else "No"
+
+            if iru:
+                length_in_country = parse_int(rows[i][s + 1].value)
+                length_out_country = parse_int(rows[i][s + 3].value)
+                iru = iru == "Yes"
+                yield nren_name, year, iru, length_in_country, length_out_country
+
+    yield from create_points_for_year(2016, 42)
+    yield from create_points_for_year(2017, 36)
+    yield from create_points_for_year(2018, 30)
+    yield from create_points_for_year(2019, 24)
+    yield from create_points_for_year(2020, 17)
+    yield from create_points_for_year(2021, 10)
+    yield from create_points_for_year(2022, 3)
+
+
+def fetch_dark_fibre_installed_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Dark Fibre"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+
+    def parse_int(excel_value):
+        if excel_value is None or excel_value == "":
+            return None
+        return int(str(excel_value).replace("-", "").replace(" ", "").replace(".", ""))
+
+    def create_points_for_year(year, start_column):
+        for i in range(10, 53):
+            nren_name = rows[i][start_column].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            s = start_column
+            if year > 2019:
+                s += 1
+            installed_length = parse_int(rows[i][s + 2].value)
+            if installed_length is not None:
+                installed = bool(installed_length)
+                yield nren_name, year, installed, installed_length
+
+    yield from create_points_for_year(2016, 42)
+    yield from create_points_for_year(2017, 36)
+    yield from create_points_for_year(2018, 30)
+    yield from create_points_for_year(2019, 24)
+    yield from create_points_for_year(2020, 17)
+    yield from create_points_for_year(2021, 10)
+    yield from create_points_for_year(2022, 3)
+
+
+def fetch_iru_duration_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "IRU duration"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+    result = {}
+
+    def create_points_for_year(year, start_column):
+        for i in range(3, 46):
+            nren_name = rows[i][start_column].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            years = rows[i][start_column + 1].value
+            if not years:
+                continue
+            years = str(years).split(" ")[0].split("+")[0].split("-")[0]
+            if not years:
+                continue
+            try:
+                years = int(years)
+            except ValueError:
+                logger.warning(f'Invalid iru duration Value :{nren_name} ({year}) with value ({years})')
+                continue
+            result[(nren_name, year)] = years
+
+    create_points_for_year(2019, 10)
+    create_points_for_year(2020, 7)
+    create_points_for_year(2021, 4)
+    create_points_for_year(2022, 1)
+    return result
+
+
+def fetch_passive_monitoring_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Traffic monitoring"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+
+    def create_points_for_year(year, start_column):
+        for i in range(6, 48):
+            nren_name = rows[i][1].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            monitoring = rows[i][start_column].value
+            method = rows[i][start_column + 1].value
+            if monitoring:
+                monitoring = monitoring == "Yes"
+                method = {
+                    "SPAN ports": MonitoringMethod.span_ports,
+                    "Passive optical TAPS": MonitoringMethod.taps,
+                    "Both": MonitoringMethod.both,
+                    None: None
+                }[method]
+                yield nren_name, year, monitoring, method
+
+    yield from create_points_for_year(2021, 4)
+    yield from create_points_for_year(2022, 2)
+
+
+def fetch_largest_link_capacity_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Largest IP Trunk capacity"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+    result = {}
+
+    def create_points_for_year(year, start_column):
+        for i in range(5, 47):
+            nren_name = rows[i][5].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            largest_capacity = rows[i][start_column].value
+            if largest_capacity:
+                result[(nren_name, year)] = int(largest_capacity)
+
+    create_points_for_year(2016, 12)
+    create_points_for_year(2017, 11)
+    create_points_for_year(2018, 10)
+    create_points_for_year(2019, 9)
+    create_points_for_year(2020, 8)
+    create_points_for_year(2021, 7)
+    create_points_for_year(2022, 6)
+    return result
+
+
+def fetch_typical_backbone_capacity_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Typical IP Trunk capacity"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+    result = {}
+
+    def create_points_for_year(year, start_column):
+        for i in range(5, 47):
+            nren_name = rows[i][4].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            typical_capacity = rows[i][start_column].value
+            if typical_capacity:
+                result[(nren_name, year)] = int(typical_capacity)
+
+    create_points_for_year(2016, 11)
+    create_points_for_year(2017, 10)
+    create_points_for_year(2018, 9)
+    create_points_for_year(2019, 8)
+    create_points_for_year(2020, 7)
+    create_points_for_year(2021, 6)
+    create_points_for_year(2022, 5)
+    return result
+
+
+def fetch_non_r_e_peers_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Peering-Non R& Network"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+
+    def create_points_for_year(year, start_column):
+        for i in range(5, 48):
+            nren_name = rows[i][2].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            nr_peers = rows[i][start_column].value
+            if nr_peers:
+                yield nren_name, year, int(nr_peers)
+
+    yield from create_points_for_year(2016, 10)
+    yield from create_points_for_year(2017, 9)
+    yield from create_points_for_year(2018, 8)
+    yield from create_points_for_year(2019, 7)
+    yield from create_points_for_year(2020, 6)
+    yield from create_points_for_year(2021, 5)
+    yield from create_points_for_year(2022, 3)
+
+
+def fetch_ops_automation_excel_data():
+    wb = openpyxl.load_workbook(EXCEL_FILE_NETWORKS, data_only=True, read_only=True)
+    sheet_name = "Automation"
+    ws = wb[sheet_name]
+    rows = list(ws.rows)
+
+    def create_points_for_year(year, start_column):
+        for i in range(5, 48):
+            nren_name = rows[i][1].value
+            if not nren_name:
+                continue
+            nren_name = nren_name.upper()
+            automation = rows[i][start_column].value
+            specifics = rows[i][start_column + 1].value or ""
+            if automation:
+                automation = YesNoPlanned[automation.lower()]
+                yield nren_name, year, automation, specifics
+
+    yield from create_points_for_year(2021, 5)
+    yield from create_points_for_year(2022, 3)
diff --git a/compendium_v2/publishers/helpers.py b/compendium_v2/publishers/helpers.py
index 1668bb90..b9c2ce68 100644
--- a/compendium_v2/publishers/helpers.py
+++ b/compendium_v2/publishers/helpers.py
@@ -33,6 +33,7 @@ def get_uppercase_nren_dict():
     nren_dict['AZSCIENCENET'] = nren_dict['ANAS']
     nren_dict['GRNET S.A.'] = nren_dict['GRNET']
     nren_dict['FUNET'] = nren_dict['CSC']
+    nren_dict['PIONEER'] = nren_dict['PIONIER']
     return nren_dict
 
 
diff --git a/compendium_v2/publishers/survey_publisher_legacy_excel.py b/compendium_v2/publishers/survey_publisher_legacy_excel.py
index fadee87a..50cb9b87 100644
--- a/compendium_v2/publishers/survey_publisher_legacy_excel.py
+++ b/compendium_v2/publishers/survey_publisher_legacy_excel.py
@@ -418,15 +418,134 @@ def db_remote_campuses_migration(nren_dict):
             connections.append({'country': country, 'local_r_and_e_connection': connected_to_r_e})
 
         nren = nren_dict[abbrev]
-        connection_carrier = presentation_models.RemoteCampuses(
+        new_entry = presentation_models.RemoteCampuses(
             nren=nren,
             nren_id=nren.id,
             year=year,
             remote_campus_connectivity=connectivity,
             connections=connections
         )
-        db.session.merge(connection_carrier)
+        db.session.merge(new_entry)
+
+    db.session.commit()
+
+
+def db_dark_fibre_lease_migration(nren_dict):
+    data_rows = excel_parser.fetch_dark_fibre_iru_excel_data()
+    iru_duration = excel_parser.fetch_iru_duration_excel_data()
+
+    for (abbrev, year, iru, length_in_country, length_out_country) in data_rows:
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
+
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.DarkFibreLease(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            iru_or_lease=iru,
+            fibre_length_in_country=length_in_country,
+            fibre_length_outside_country=length_out_country,
+            iru_duration=iru_duration.get((abbrev, year))
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
+def db_dark_fibre_installed_migration(nren_dict):
+    data_rows = excel_parser.fetch_dark_fibre_installed_excel_data()
+    for (abbrev, year, installed, length) in data_rows:
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
+
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.DarkFibreInstalled(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            installed=installed,
+            fibre_length_in_country=length
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
+def db_passive_monitoring_migration(nren_dict):
+    data_rows = excel_parser.fetch_passive_monitoring_excel_data()
+    for (abbrev, year, monitoring, method) in data_rows:
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
+
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.PassiveMonitoring(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            monitoring=monitoring,
+            method=method
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
+def db_capacity_migration(nren_dict):
+    largest_data_rows = excel_parser.fetch_largest_link_capacity_excel_data()
+    typical_data_rows = excel_parser.fetch_typical_backbone_capacity_excel_data()
+
+    for abbrev, year in largest_data_rows.keys() | typical_data_rows.keys():
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
+
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.Capacity(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            largest_link_capacity=largest_data_rows.get((abbrev, year)),
+            typical_backbone_capacity=typical_data_rows.get((abbrev, year))
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
+def db_non_r_e_peers_migration(nren_dict):
+    data_rows = excel_parser.fetch_non_r_e_peers_excel_data()
+    for (abbrev, year, nr_of_non_r_and_e_peers) in data_rows:
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
 
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.NonREPeers(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            nr_of_non_r_and_e_peers=nr_of_non_r_and_e_peers
+        )
+        db.session.merge(new_entry)
+    db.session.commit()
+
+
+def db_ops_automation_migration(nren_dict):
+    data_rows = excel_parser.fetch_ops_automation_excel_data()
+    for (abbrev, year, automation, specifics) in data_rows:
+        if abbrev not in nren_dict:
+            logger.warning(f'{abbrev} unknown. Skipping.')
+            continue
+
+        nren = nren_dict[abbrev]
+        new_entry = presentation_models.OpsAutomation(
+            nren=nren,
+            nren_id=nren.id,
+            year=year,
+            ops_automation=automation,
+            ops_automation_specifics=specifics
+        )
+        db.session.merge(new_entry)
     db.session.commit()
 
 
@@ -450,6 +569,13 @@ def _cli(app):
         db_connectivity_load_migration(nren_dict)
         db_remote_campuses_migration(nren_dict)
 
+        db_dark_fibre_lease_migration(nren_dict)
+        db_dark_fibre_installed_migration(nren_dict)
+        db_passive_monitoring_migration(nren_dict)
+        db_capacity_migration(nren_dict)
+        db_non_r_e_peers_migration(nren_dict)
+        db_ops_automation_migration(nren_dict)
+
 
 @click.command()
 @click.option('--config', type=click.STRING, default='config.json')
diff --git a/test/test_survey_publisher_legacy_excel.py b/test/test_survey_publisher_legacy_excel.py
index b066767e..9a14b393 100644
--- a/test/test_survey_publisher_legacy_excel.py
+++ b/test/test_survey_publisher_legacy_excel.py
@@ -13,7 +13,8 @@ def test_excel_publisher(app_with_survey_db, mocker):
     mocker.patch('compendium_v2.publishers.excel_parser.EXCEL_FILE_ORGANISATION', EXCEL_FILE)
 
     with app_with_survey_db.app_context():
-        nren_names = ['SURF', 'KIFU', 'University of Malta', 'ASNET-AM', 'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC']
+        nren_names = ['SURF', 'KIFU', 'University of Malta', 'ASNET-AM', 'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC',
+                      'PIONIER']
         db.session.add_all([presentation_models.NREN(name=nren_name, country='country') for nren_name in nren_names])
         db.session.commit()
 
diff --git a/test/test_survey_publisher_old_db_2022.py b/test/test_survey_publisher_old_db_2022.py
index 7b2983f9..39259ab6 100644
--- a/test/test_survey_publisher_old_db_2022.py
+++ b/test/test_survey_publisher_old_db_2022.py
@@ -210,7 +210,7 @@ def test_publisher(app_with_survey_db, mocker):
     mocker.patch('compendium_v2.publishers.survey_publisher_old_db_2022.recursive_query', institutions_urls_data)
 
     nren_names = ['Nren1', 'Nren2', 'Nren3', 'Nren4', 'SURF', 'KIFU', 'University of Malta', 'ASNET-AM',
-                  'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC']
+                  'SIKT', 'LAT', 'RASH', 'ANAS', 'GRNET', 'CSC', 'PIONIER']
     with app_with_survey_db.app_context():
         db.session.add_all([presentation_models.NREN(name=nren_name, country='country') for nren_name in nren_names])
         db.session.commit()
-- 
GitLab