Loading .dockerignore +10 −1 Original line number Diff line number Diff line Loading @@ -17,3 +17,12 @@ __pycache__/ *.db .env .git/ .venv/ venv/ *.venv/ .pytest_cache/ .coverage htmlcov/ *.egg-info/ .idea/ .vscode/ No newline at end of file .gitignore +3 −0 Original line number Diff line number Diff line Loading @@ -18,4 +18,7 @@ src/__pycache__/ venv/ .env slice.db service.db telemetry_client.db alert.db .python-version src/api/main.py +18 −14 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ from src.database.sysrepo_store import get_data_store, create_data_store, delete from typing import Dict, Tuple from src.realizer.restconf.connectors.tfs_connector import tfs_connector as tfs_restconf_connector from src.planner.shortest_path import get_shortest_path from src.realizer.tfs.service_types.tfs_l2vpn import tfs_l2vpn_delete Loading Loading @@ -56,6 +57,8 @@ class Api: result = self.slice_service.nsc(intent) if not result: return send_response(False, code=404, message="No intents found") if isinstance(result, tuple): return result logging.info(f"Slice created successfully") return send_response( True, Loading Loading @@ -358,6 +361,8 @@ class Api: """ try: result = self.slice_service.nsc(intent, slice_id) if isinstance(result, tuple): return result if not result: return send_response(False, code=404, message="Slice not found") logging.info(f"Slice {slice_id} modified successfully") Loading Loading @@ -435,7 +440,7 @@ class Api: logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice.get("slice_id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() # Clear slice database delete_all_data() Loading Loading @@ -532,8 +537,13 @@ class Api: def add_network_slice_service(self, intent): try: result = self.slice_service.nsc(intent) if isinstance(result, tuple): return result if result: try: create_data_store(intent) except Exception as ds_err: logging.warning(f"Could not store intent in sysrepo datastore: {ds_err}") logging.info(f"Network Slice created successfully") return send_response( True, Loading Loading @@ -904,18 +914,15 @@ class Api: if not existing_slice: raise ValueError("Slice not found") if not current_app.config["DUMMY_MODE"]: slice_type = list(existing_slice["network-slice-services"]["slice-service"][slice_id]["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") slice_type = safe_get(existing_slice, ["network-slice-services", "slice-service", slice_id, "service-tags", "tag-type", "ietf-network-slice-service:service", "tag-type-value", 0]) or "L2" logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") services = get_data_by_slice_id(existing_slice.get("id")) services = get_data_by_slice_id(slice_id) for service in services: id = service.get("service_id") tfs_connector().nbi_delete(current_app.config["RESTCONF_IP"], slice_type, id) delete_by_slice_id(slice.get("id")) delete_by_slice_id(slice_id) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() delete_data_store(xpath) logging.info(f"Slice {slice_id} removed successfully") Loading @@ -930,10 +937,7 @@ class Api: if not slice_services: raise ValueError("Slice services not found") for slice in slice_services: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") slice_type = safe_get(slice, ["service-tags", "tag-type", "ietf-network-slice-service:service", "tag-type-value", 0]) or "L2" logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") services = get_data_by_slice_id(slice.get("id")) for service in services: Loading @@ -941,7 +945,7 @@ class Api: tfs_connector().nbi_delete(current_app.config["RESTCONF_IP"], slice_type, id) delete_by_slice_id(slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 Loading src/database/service_db.py +23 −19 Original line number Diff line number Diff line Loading @@ -61,23 +61,25 @@ def save_data(service_id: str, slice_id: str): # Update data in the database def update_data(service_id: str, new_slice_id: str): """ Update an existing service entry in the database. Update the slice_id for an existing service entry in the database. Args: service_id (str): Unique identifier for the service slice_id (str): Unique identifier for the slice service_id (str): Unique identifier for the service to update new_slice_id (str): New slice ID to associate with the service Raises: ValueError: If no service is found with the given service_id """ conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() try: cursor.execute("UPDATE service SET slice_id = ? WHERE service_id = ?", (new_slice_id, service_id)) if cursor.rowcount == 0: raise ValueError(f"No slice found with id '{service_id}' to update.") else: logging.debug(f"Slice '{service_id}' updated.") conn.commit() finally: conn.close() # Delete data from the database Loading @@ -93,12 +95,14 @@ def delete_data(service_id: str): """ conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() try: cursor.execute("DELETE FROM service WHERE service_id = ?", (service_id,)) if cursor.rowcount == 0: raise ValueError(f"No service found with id '{service_id}' to delete.") else: logging.debug(f"Service '{service_id}' deleted.") conn.commit() finally: conn.close() # Get data from the database Loading src/database/sysrepo_store.py +21 −5 Original line number Diff line number Diff line Loading @@ -255,13 +255,29 @@ def _write_dict(sess, base_xpath, data, parent_key=None): key_field = LIST_KEYS.get(list_name) for item in data: if key_field and isinstance(item, dict) and key_field in item: key_value = item[key_field] item_xpath = f"{base_xpath}[{key_field}='{key_value}']" logging.debug(f"Using key '{key_field}={key_value}' for list '{list_name}'") if item is None: continue item_key_field = key_field if (not item_key_field or item_key_field not in item) and isinstance(item, dict): for candidate in ["sliceProfileId", "serviceProfileId", "id", "uuid", "name"]: if candidate in item: item_key_field = candidate break if not item_key_field: for k in item.keys(): if k.lower().endswith("id"): item_key_field = k break if not item_key_field and item: item_key_field = list(item.keys())[0] if item_key_field and isinstance(item, dict) and item_key_field in item: key_value = item[item_key_field] item_xpath = f"{base_xpath}[{item_key_field}='{key_value}']" logging.debug(f"Using key '{item_key_field}={key_value}' for list '{list_name}'") # Pass the key_field to be excluded when processing the item _write_dict(sess, item_xpath, item, parent_key=key_field) _write_dict(sess, item_xpath, item, parent_key=item_key_field) else: logging.error(f"ERROR: No key '{key_field}' found in item for list '{list_name}'") logging.error(f"Available keys in item: {list(item.keys()) if isinstance(item, dict) else 'N/A'}") Loading Loading
.dockerignore +10 −1 Original line number Diff line number Diff line Loading @@ -17,3 +17,12 @@ __pycache__/ *.db .env .git/ .venv/ venv/ *.venv/ .pytest_cache/ .coverage htmlcov/ *.egg-info/ .idea/ .vscode/ No newline at end of file
.gitignore +3 −0 Original line number Diff line number Diff line Loading @@ -18,4 +18,7 @@ src/__pycache__/ venv/ .env slice.db service.db telemetry_client.db alert.db .python-version
src/api/main.py +18 −14 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ from src.database.sysrepo_store import get_data_store, create_data_store, delete from typing import Dict, Tuple from src.realizer.restconf.connectors.tfs_connector import tfs_connector as tfs_restconf_connector from src.planner.shortest_path import get_shortest_path from src.realizer.tfs.service_types.tfs_l2vpn import tfs_l2vpn_delete Loading Loading @@ -56,6 +57,8 @@ class Api: result = self.slice_service.nsc(intent) if not result: return send_response(False, code=404, message="No intents found") if isinstance(result, tuple): return result logging.info(f"Slice created successfully") return send_response( True, Loading Loading @@ -358,6 +361,8 @@ class Api: """ try: result = self.slice_service.nsc(intent, slice_id) if isinstance(result, tuple): return result if not result: return send_response(False, code=404, message="Slice not found") logging.info(f"Slice {slice_id} modified successfully") Loading Loading @@ -435,7 +440,7 @@ class Api: logging.warning(f"Slice type not found in slice intent. Defaulting to L2") tfs_connector().nbi_delete(current_app.config["TFS_IP"],slice_type, slice.get("slice_id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() # Clear slice database delete_all_data() Loading Loading @@ -532,8 +537,13 @@ class Api: def add_network_slice_service(self, intent): try: result = self.slice_service.nsc(intent) if isinstance(result, tuple): return result if result: try: create_data_store(intent) except Exception as ds_err: logging.warning(f"Could not store intent in sysrepo datastore: {ds_err}") logging.info(f"Network Slice created successfully") return send_response( True, Loading Loading @@ -904,18 +914,15 @@ class Api: if not existing_slice: raise ValueError("Slice not found") if not current_app.config["DUMMY_MODE"]: slice_type = list(existing_slice["network-slice-services"]["slice-service"][slice_id]["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") slice_type = safe_get(existing_slice, ["network-slice-services", "slice-service", slice_id, "service-tags", "tag-type", "ietf-network-slice-service:service", "tag-type-value", 0]) or "L2" logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") services = get_data_by_slice_id(existing_slice.get("id")) services = get_data_by_slice_id(slice_id) for service in services: id = service.get("service_id") tfs_connector().nbi_delete(current_app.config["RESTCONF_IP"], slice_type, id) delete_by_slice_id(slice.get("id")) delete_by_slice_id(slice_id) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() delete_data_store(xpath) logging.info(f"Slice {slice_id} removed successfully") Loading @@ -930,10 +937,7 @@ class Api: if not slice_services: raise ValueError("Slice services not found") for slice in slice_services: slice_type = list(slice["service-tags"]["tag-type"]["ietf-network-slice-service:service"]["tag-type-value"])[0] if not slice_type: slice_type = "L2" logging.warning(f"Slice type not found in slice intent. Defaulting to L2") slice_type = safe_get(slice, ["service-tags", "tag-type", "ietf-network-slice-service:service", "tag-type-value", 0]) or "L2" logging.debug(f"Send slice to delete in TFS with slice_type {slice_type}") services = get_data_by_slice_id(slice.get("id")) for service in services: Loading @@ -941,7 +945,7 @@ class Api: tfs_connector().nbi_delete(current_app.config["RESTCONF_IP"], slice_type, id) delete_by_slice_id(slice.get("id")) if current_app.config["TFS_L2VPN_SUPPORT"]: self.slice_service.tfs_l2vpn_delete() tfs_l2vpn_delete() delete_data_store(xpath) logging.info("All slices removed successfully") return {}, 204 Loading
src/database/service_db.py +23 −19 Original line number Diff line number Diff line Loading @@ -61,23 +61,25 @@ def save_data(service_id: str, slice_id: str): # Update data in the database def update_data(service_id: str, new_slice_id: str): """ Update an existing service entry in the database. Update the slice_id for an existing service entry in the database. Args: service_id (str): Unique identifier for the service slice_id (str): Unique identifier for the slice service_id (str): Unique identifier for the service to update new_slice_id (str): New slice ID to associate with the service Raises: ValueError: If no service is found with the given service_id """ conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() try: cursor.execute("UPDATE service SET slice_id = ? WHERE service_id = ?", (new_slice_id, service_id)) if cursor.rowcount == 0: raise ValueError(f"No slice found with id '{service_id}' to update.") else: logging.debug(f"Slice '{service_id}' updated.") conn.commit() finally: conn.close() # Delete data from the database Loading @@ -93,12 +95,14 @@ def delete_data(service_id: str): """ conn = sqlite3.connect(DB_NAME) cursor = conn.cursor() try: cursor.execute("DELETE FROM service WHERE service_id = ?", (service_id,)) if cursor.rowcount == 0: raise ValueError(f"No service found with id '{service_id}' to delete.") else: logging.debug(f"Service '{service_id}' deleted.") conn.commit() finally: conn.close() # Get data from the database Loading
src/database/sysrepo_store.py +21 −5 Original line number Diff line number Diff line Loading @@ -255,13 +255,29 @@ def _write_dict(sess, base_xpath, data, parent_key=None): key_field = LIST_KEYS.get(list_name) for item in data: if key_field and isinstance(item, dict) and key_field in item: key_value = item[key_field] item_xpath = f"{base_xpath}[{key_field}='{key_value}']" logging.debug(f"Using key '{key_field}={key_value}' for list '{list_name}'") if item is None: continue item_key_field = key_field if (not item_key_field or item_key_field not in item) and isinstance(item, dict): for candidate in ["sliceProfileId", "serviceProfileId", "id", "uuid", "name"]: if candidate in item: item_key_field = candidate break if not item_key_field: for k in item.keys(): if k.lower().endswith("id"): item_key_field = k break if not item_key_field and item: item_key_field = list(item.keys())[0] if item_key_field and isinstance(item, dict) and item_key_field in item: key_value = item[item_key_field] item_xpath = f"{base_xpath}[{item_key_field}='{key_value}']" logging.debug(f"Using key '{item_key_field}={key_value}' for list '{list_name}'") # Pass the key_field to be excluded when processing the item _write_dict(sess, item_xpath, item, parent_key=key_field) _write_dict(sess, item_xpath, item, parent_key=item_key_field) else: logging.error(f"ERROR: No key '{key_field}' found in item for list '{list_name}'") logging.error(f"Available keys in item: {list(item.keys()) if isinstance(item, dict) else 'N/A'}") Loading