From 2ac5f0f83c7be36836be36aceaba00cdd8040a6a Mon Sep 17 00:00:00 2001
From: gifrerenom <lluis.gifre@cttc.es>
Date: Mon, 30 Sep 2024 17:06:29 +0000
Subject: [PATCH] Deployed microservices:

- Added method to check deployed microservices
- Extended WebUI to activate tabs according to deployed microservices
- Extended Service and PathComp to activate selective parts of code depending on deployed microservices
---
 src/common/Settings.py                        | 18 ++++
 src/pathcomp/frontend/Config.py               |  3 +-
 .../service/ServiceServiceServicerImpl.py     | 13 +--
 src/service/service/__main__.py               |  2 -
 src/webui/service/__init__.py                 |  9 ++
 src/webui/service/__main__.py                 |  2 -
 src/webui/service/templates/base.html         | 89 +++++++++++--------
 7 files changed, 91 insertions(+), 45 deletions(-)

diff --git a/src/common/Settings.py b/src/common/Settings.py
index eaeb363ad..e85228527 100644
--- a/src/common/Settings.py
+++ b/src/common/Settings.py
@@ -108,3 +108,21 @@ def get_grpc_grace_period():
 
 def get_http_bind_address():
     return get_setting(ENVVAR_HTTP_BIND_ADDRESS, default=DEFAULT_HTTP_BIND_ADDRESS)
+
+
+##### ----- Detect deployed microservices ----- #####
+
+def is_microservice_deployed(service_name : ServiceNameEnum) -> bool:
+    host_env_var_name = get_env_var_name(service_name, ENVVAR_SUFIX_SERVICE_HOST     )
+    port_env_var_name = get_env_var_name(service_name, ENVVAR_SUFIX_SERVICE_PORT_GRPC)
+    return (host_env_var_name in os.environ) and (port_env_var_name in os.environ)
+
+def is_deployed_bgpls     () -> bool: return is_microservice_deployed(ServiceNameEnum.BGPLS            )
+def is_deployed_e2e_orch  () -> bool: return is_microservice_deployed(ServiceNameEnum.E2EORCHESTRATOR  )
+def is_deployed_forecaster() -> bool: return is_microservice_deployed(ServiceNameEnum.FORECASTER       )
+def is_deployed_load_gen  () -> bool: return is_microservice_deployed(ServiceNameEnum.LOAD_GENERATOR   )
+def is_deployed_optical   () -> bool: return is_microservice_deployed(ServiceNameEnum.OPTICALCONTROLLER)
+def is_deployed_policy    () -> bool: return is_microservice_deployed(ServiceNameEnum.POLICY           )
+def is_deployed_qkd_app   () -> bool: return is_microservice_deployed(ServiceNameEnum.QKD_APP          )
+def is_deployed_slice     () -> bool: return is_microservice_deployed(ServiceNameEnum.SLICE            )
+def is_deployed_te        () -> bool: return is_microservice_deployed(ServiceNameEnum.TE               )
diff --git a/src/pathcomp/frontend/Config.py b/src/pathcomp/frontend/Config.py
index 08de81b47..ab431acb9 100644
--- a/src/pathcomp/frontend/Config.py
+++ b/src/pathcomp/frontend/Config.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import os
-from common.Settings import get_setting
+from common.Settings import get_setting, is_deployed_forecaster
 
 DEFAULT_PATHCOMP_BACKEND_SCHEME  = 'http'
 DEFAULT_PATHCOMP_BACKEND_HOST    = '127.0.0.1'
@@ -44,6 +44,7 @@ SETTING_NAME_ENABLE_FORECASTER = 'ENABLE_FORECASTER'
 TRUE_VALUES = {'Y', 'YES', 'TRUE', 'T', 'E', 'ENABLE', 'ENABLED'}
 
 def is_forecaster_enabled() -> bool:
+    if not is_deployed_forecaster(): return False
     is_enabled = get_setting(SETTING_NAME_ENABLE_FORECASTER, default=None)
     if is_enabled is None: return False
     str_is_enabled = str(is_enabled).upper()
diff --git a/src/service/service/ServiceServiceServicerImpl.py b/src/service/service/ServiceServiceServicerImpl.py
index eb821972a..45a8e0b6c 100644
--- a/src/service/service/ServiceServiceServicerImpl.py
+++ b/src/service/service/ServiceServiceServicerImpl.py
@@ -30,6 +30,9 @@ from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_s
 from common.tools.object_factory.Context import json_context_id
 from common.tools.object_factory.Topology import json_topology_id
 from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.Settings import (
+    is_deployed_e2e_orch, is_deployed_optical, is_deployed_te
+)
 from context.client.ContextClient import ContextClient
 from e2e_orchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
 from pathcomp.frontend.client.PathCompClient import PathCompClient
@@ -142,7 +145,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
             service.service_type = request.service_type                                     # pylint: disable=no-member
         service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED     # pylint: disable=no-member
 
-        if service.service_type == ServiceTypeEnum.SERVICETYPE_TE:
+        if is_deployed_te() and service.service_type == ServiceTypeEnum.SERVICETYPE_TE:
             # TE service:
             context_client.SetService(request)
 
@@ -164,7 +167,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
                 str_service_status = ServiceStatusEnum.Name(service_status.service_status)
                 raise Exception(MSG.format(service_key, str_service_status))
 
-        if service.service_type == ServiceTypeEnum.SERVICETYPE_E2E:
+        if is_deployed_e2e_orch() and service.service_type == ServiceTypeEnum.SERVICETYPE_E2E:
             # End-to-End service:
             service_id_with_uuids = context_client.SetService(request)
 
@@ -248,7 +251,7 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
 
         tasks_scheduler = TasksScheduler(self.service_handler_factory)
 
-        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+        if is_deployed_optical() and service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
             context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
             topology_id_x = json_topology_id(
                 DEFAULT_TOPOLOGY_NAME, context_id_x)
@@ -341,14 +344,14 @@ class ServiceServiceServicerImpl(ServiceServiceServicer):
         service.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PENDING_REMOVAL
         context_client.SetService(service)
 
-        if service.service_type == ServiceTypeEnum.SERVICETYPE_TE:
+        if is_deployed_te() and service.service_type == ServiceTypeEnum.SERVICETYPE_TE:
             # TE service
             te_service_client = TEServiceClient()
             te_service_client.DeleteLSP(request)
             context_client.RemoveService(request)
             return Empty()
 
-        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+        if is_deployed_optical() and service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
             devs = []
 
             context_id_x = json_context_id(DEFAULT_CONTEXT_NAME)
diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py
index 5f9f2fa3a..ae8a9e960 100644
--- a/src/service/service/__main__.py
+++ b/src/service/service/__main__.py
@@ -44,8 +44,6 @@ def main():
         get_env_var_name(ServiceNameEnum.DEVICE,   ENVVAR_SUFIX_SERVICE_PORT_GRPC),
         get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_HOST     ),
         get_env_var_name(ServiceNameEnum.PATHCOMP, ENVVAR_SUFIX_SERVICE_PORT_GRPC),
-        get_env_var_name(ServiceNameEnum.QKD_APP,  ENVVAR_SUFIX_SERVICE_HOST     ),
-        get_env_var_name(ServiceNameEnum.QKD_APP,  ENVVAR_SUFIX_SERVICE_PORT_GRPC),
     ])
 
     signal.signal(signal.SIGINT,  signal_handler)
diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py
index f269408e4..f137c247e 100644
--- a/src/webui/service/__init__.py
+++ b/src/webui/service/__init__.py
@@ -20,6 +20,9 @@ from common.tools.grpc.Tools import grpc_message_to_json
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from qkd_app.client.QKDAppClient import QKDAppClient
+from common.Settings import (
+    is_deployed_bgpls, is_deployed_load_gen, is_deployed_policy, is_deployed_qkd_app, is_deployed_slice
+)
 
 def get_working_context() -> str:
     return session['context_uuid'] if 'context_uuid' in session else '---'
@@ -120,6 +123,12 @@ def create_app(use_config=None, web_app_root=None):
         'round'               : round,
         'get_working_context' : get_working_context,
         'get_working_topology': get_working_topology,
+
+        'is_deployed_bgpls'   : is_deployed_bgpls,
+        'is_deployed_load_gen': is_deployed_load_gen,
+        'is_deployed_policy'  : is_deployed_policy,
+        'is_deployed_qkd_app' : is_deployed_qkd_app,
+        'is_deployed_slice'   : is_deployed_slice,
     })
 
     if web_app_root is not None:
diff --git a/src/webui/service/__main__.py b/src/webui/service/__main__.py
index 8ec8dcb64..bb6b8bfc7 100644
--- a/src/webui/service/__main__.py
+++ b/src/webui/service/__main__.py
@@ -43,8 +43,6 @@ def main():
         get_env_var_name(ServiceNameEnum.SERVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC),
         get_env_var_name(ServiceNameEnum.SLICE,   ENVVAR_SUFIX_SERVICE_HOST     ),
         get_env_var_name(ServiceNameEnum.SLICE,   ENVVAR_SUFIX_SERVICE_PORT_GRPC),
-        get_env_var_name(ServiceNameEnum.QKD_APP, ENVVAR_SUFIX_SERVICE_HOST     ),
-        get_env_var_name(ServiceNameEnum.QKD_APP, ENVVAR_SUFIX_SERVICE_PORT_GRPC),
     ])
 
     logger.info('Starting...')
diff --git a/src/webui/service/templates/base.html b/src/webui/service/templates/base.html
index 9cea0a59d..432f1a095 100644
--- a/src/webui/service/templates/base.html
+++ b/src/webui/service/templates/base.html
@@ -55,6 +55,7 @@
                   <a class="nav-link" href="{{ url_for('main.home') }}">Home</a>
                   {% endif %}
                 </li>
+
                 <li class="nav-item">
                   {% if '/device/' in request.path %}
                   <a class="nav-link active" aria-current="page" href="{{ url_for('device.home') }}">Device</a>
@@ -62,6 +63,7 @@
                   <a class="nav-link" href="{{ url_for('device.home') }}">Device</a>
                   {% endif %}
                 </li>
+
                 <li class="nav-item">
                   {% if '/link/' in request.path %}
                   <a class="nav-link active" aria-current="page" href="{{ url_for('link.home') }}">Link</a>
@@ -69,6 +71,7 @@
                   <a class="nav-link" href="{{ url_for('link.home') }}">Link</a>
                   {% endif %}
                 </li>
+
                 <li class="nav-item">
                   {% if '/service/' in request.path %}
                   <a class="nav-link active" aria-current="page" href="{{ url_for('service.home') }}">Service</a>
@@ -76,47 +79,63 @@
                   <a class="nav-link" href="{{ url_for('service.home') }}">Service</a>
                   {% endif %}
                 </li>
-                <li class="nav-item">
-                  {% if '/slice/' in request.path %}
-                  <a class="nav-link active" aria-current="page" href="{{ url_for('slice.home') }}">Slice</a>
-                  {% else %}
-                  <a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a>
-                  {% endif %}
-                </li>
-                <li class="nav-item">
-                  {% if '/policy_rule/' in request.path %}
-                  <a class="nav-link active" aria-current="page" href="{{ url_for('policy_rule.home') }}">Policy Rules</a>
-                  {% else %}
-                  <a class="nav-link" href="{{ url_for('policy_rule.home') }}">Policy Rules</a>
-                  {% endif %}
-                </li>
+
+                {% if is_deployed_slice() %}
+                  <li class="nav-item">
+                    {% if '/slice/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('slice.home') }}">Slice</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a>
+                    {% endif %}
+                  </li>
+                {% endif %}
+
+                {% if is_deployed_policy() %}
+                  <li class="nav-item">
+                    {% if '/policy_rule/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('policy_rule.home') }}">Policy Rules</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('policy_rule.home') }}">Policy Rules</a>
+                    {% endif %}
+                  </li>
+                {% endif %}
+
+                {% if is_deployed_qkd_app() %}
+                  <li class="nav-item">
+                    {% if '/qkd_app/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('qkd_app.home') }}">QKD Apps</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('qkd_app.home') }}">QKD Apps</a>
+                    {% endif %}
+                  </li> 
+                {% endif %}
+
+                {% if is_deployed_bgpls() %}
+                  <li class="nav-item">
+                    {% if '/bgpls/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('bgpls.home') }}">BGPLS</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('bgpls.home') }}">BGPLS</a>
+                    {% endif %}
+                  </li>
+                {% endif %}
+
+                {% if is_deployed_load_gen() %}
+                  <li class="nav-item">
+                    {% if '/load-gen/' in request.path %}
+                    <a class="nav-link active" aria-current="page" href="{{ url_for('load_gen.home') }}">Load Generator</a>
+                    {% else %}
+                    <a class="nav-link" href="{{ url_for('load_gen.home') }}">Load Generator</a>
+                    {% endif %}
+                  </li>
+                {% endif %}
+
                 <li class="nav-item">
                   <a class="nav-link" href="/grafana" id="grafana_link" target="grafana">Grafana</a>
                 </li>
                 <li class="nav-item">
                   <a class="nav-link" href="{{ url_for('main.debug') }}">Debug</a>
                 </li>
-                <li class="nav-item">
-                  {% if '/load-gen/' in request.path %}
-                  <a class="nav-link active" aria-current="page" href="{{ url_for('load_gen.home') }}">Load Generator</a>
-                  {% else %}
-                  <a class="nav-link" href="{{ url_for('load_gen.home') }}">Load Generator</a>
-                  {% endif %}
-                </li>
-                <li class="nav-item">
-                  {% if '/qkd_app/' in request.path %}
-                  <a class="nav-link active" aria-current="page" href="{{ url_for('qkd_app.home') }}">QKD Apps</a>
-                  {% else %}
-                  <a class="nav-link" href="{{ url_for('qkd_app.home') }}">QKD Apps</a>
-                  {% endif %}
-                </li> 
-                <li class="nav-item">
-                  {% if '/bgpls/' in request.path %}
-                  <a class="nav-link active" aria-current="page" href="{{ url_for('bgpls.home') }}">BGPLS</a>
-                  {% else %}
-                  <a class="nav-link" href="{{ url_for('bgpls.home') }}">BGPLS</a>
-                  {% endif %}
-                </li>
   
                 <!-- <li class="nav-item">
                   <a class="nav-link" href="#">Context</a>
-- 
GitLab