diff --git a/deploy/tfs.sh b/deploy/tfs.sh index 3fdbe77fb502c42aaf7dd507ab239f6b3bb20056..285acc46532f0c38917268750438e3af7cc6ba93 100755 --- a/deploy/tfs.sh +++ b/deploy/tfs.sh @@ -46,6 +46,26 @@ export TFS_GRAFANA_PASSWORD=${TFS_GRAFANA_PASSWORD:-"admin123+"} export TFS_SKIP_BUILD=${TFS_SKIP_BUILD:-""} +# ----- App CockroachDB -------------------------------------------------------- + +# If not already set, set the namespace where CockroackDB will be deployed. +export APP_CRDB_NAMESPACE=${APP_CRDB_NAMESPACE:-"app-crdb"} + +# If not already set, set the external port CockroackDB Postgre SQL interface will be exposed to. +export APP_CRDB_EXT_PORT_SQL=${APP_CRDB_EXT_PORT_SQL:-"26257"} + +# If not already set, set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to. +export APP_CRDB_EXT_PORT_HTTP=${APP_CRDB_EXT_PORT_HTTP:-"8081"} + +# If not already set, set the database username to be used by Context. +export APP_CRDB_USERNAME=${APP_CRDB_USERNAME:-"tfs"} + +# If not already set, set the database user's password to be used by Context. +export APP_CRDB_PASSWORD=${APP_CRDB_PASSWORD:-"tfs123"} + +# If not already set, set the database name to be used by Context. +export APP_CRDB_DATABASE=${APP_CRDB_DATABASE:-"tfs"} + # ----- CockroachDB ------------------------------------------------------------ # If not already set, set the namespace where CockroackDB will be deployed. @@ -141,6 +161,7 @@ kubectl create secret generic crdb-data --namespace ${TFS_K8S_NAMESPACE} --type= --from-literal=CRDB_NAMESPACE=${CRDB_NAMESPACE} \ --from-literal=CRDB_SQL_PORT=${CRDB_SQL_PORT} \ --from-literal=CRDB_DATABASE=${CRDB_DATABASE} \ + --from-literal=CRDB_DATABASE_APP=${CRDB_DATABASE_APP} \ --from-literal=CRDB_USERNAME=${CRDB_USERNAME} \ --from-literal=CRDB_PASSWORD=${CRDB_PASSWORD} \ --from-literal=CRDB_SSLMODE=require diff --git a/manifests/appservice.yaml b/manifests/appservice.yaml new file mode 100644 index 0000000000000000000000000000000000000000..da0a073538ecd1a194a4b356b248c5c70a18f974 --- /dev/null +++ b/manifests/appservice.yaml @@ -0,0 +1,83 @@ +# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: appservice +spec: + selector: + matchLabels: + app: appservice + #replicas: 1 + template: + metadata: + labels: + app: appservice + spec: + terminationGracePeriodSeconds: 5 + containers: + - name: server + image: labs.etsi.org:5050/tfs/controller/app:latest + imagePullPolicy: Always + ports: + - containerPort: 10060 + - containerPort: 9192 + - containerPort: 8005 + env: + - name: MB_BACKEND + value: "nats" + - name: LOG_LEVEL + value: "INFO" + envFrom: + - secretRef: + name: crdb-data + - secretRef: + name: nats-data + readinessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:10060"] + livenessProbe: + exec: + command: ["/bin/grpc_health_probe", "-addr=:10060"] + resources: + requests: + cpu: 150m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi +--- +apiVersion: v1 +kind: Service +metadata: + name: appservice + labels: + app: appservice +spec: + type: ClusterIP + selector: + app: appservice + ports: + - name: grpc + protocol: TCP + port: 10060 + targetPort: 10060 + - name: metrics + protocol: TCP + port: 9192 + targetPort: 9192 + - name: app + port: 8005 + targetPort: 8005 diff --git a/manifests/nginx_ingress_http.yaml b/manifests/nginx_ingress_http.yaml index 0892f0c9b790b936df5540ac5fe1aed0270b91a5..249501afade8f4dc5f6c9eb632602c1d0fefb530 100644 --- a/manifests/nginx_ingress_http.yaml +++ b/manifests/nginx_ingress_http.yaml @@ -57,3 +57,10 @@ spec: name: nbiservice port: number: 8080 + - path: /()(app/.*) + - pathType: Prefix + backend: + service: + name: appservice + port: + number: 8005 diff --git a/my_deploy.sh b/my_deploy.sh index 8417f6eae510391e65d5f91202e59cccf32e1f98..b52434d33d58029335e24952c63b65befb0be0e1 100755 --- a/my_deploy.sh +++ b/my_deploy.sh @@ -20,13 +20,13 @@ export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/" # Set the list of components, separated by spaces, you want to build images for, and deploy. -export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator" +export TFS_COMPONENTS="context device app pathcomp service slice nbi webui load_generator" # Uncomment to activate Monitoring #export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring" # Uncomment to activate BGP-LS Speaker -#export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker" +export TFS_COMPONENTS="${TFS_COMPONENTS} bgpls_speaker" # Uncomment to activate Optical Controller # To manage optical connections, "service" requires "opticalcontroller" to be deployed @@ -100,6 +100,7 @@ export CRDB_PASSWORD="tfs123" # Set the database name to be used by Context. export CRDB_DATABASE="tfs" +export CRDB_DATABASE_APP="tfs_app" # Set CockroachDB installation mode to 'single'. This option is convenient for development and testing. # See ./deploy/all.sh or ./deploy/crdb.sh for additional details diff --git a/proto/app.proto b/proto/app.proto new file mode 100644 index 0000000000000000000000000000000000000000..d2ed33500da412fad1e8af3ebc709136e4cf46a8 --- /dev/null +++ b/proto/app.proto @@ -0,0 +1,53 @@ +syntax = "proto3"; +package app; + +import "context.proto"; + +// Optare: Change this if you want to change App's structure or enums. +// Optare: If a message (structure) is changed it must be changed in src/app/service/database + +enum QKDAppStatusEnum { + QKDAPPSTATUS_ON = 0; + QKDAPPSTATUS_DISCONNECTED = 1; + QKDAPPSTATUS_OUT_OF_TIME = 2; + QKDAPPSTATUS_ZOMBIE = 3; +} + +enum QKDAppTypesEnum { + QKDAPPTYPES_INTERNAL = 0; + QKDAPPTYPES_CLIENT = 1; +} + +message QKDLId { + context.Uuid qkdl_uuid = 1; +} + + +message App { + AppId app_id = 1; + QKDAppStatusEnum app_status = 2; + QKDAppTypesEnum app_type = 3; + string server_app_id = 4; + repeated string client_app_id = 5; + repeated QKDLId backing_qkdl_id = 6; + context.DeviceId local_device_id = 7; + context.DeviceId remote_device_id = 8; +} + + +message AppId { + context.ContextId context_id = 1; + context.Uuid app_uuid = 2; +} + + +service AppService { + rpc RegisterApp(App) returns (context.Empty) {} + rpc ListApps (context.ContextId ) returns ( AppList ) {} + } + + + + message AppList { + repeated App apps = 1; +} diff --git a/src/app/client/AppClient b/src/app/client/AppClient.py similarity index 100% rename from src/app/client/AppClient rename to src/app/client/AppClient.py diff --git a/src/common/Constants.py b/src/common/Constants.py index de9ac45a4089a7847c37ceeeeab000f51566a3a3..511735ea4b03cce00eb91242975983d6b58c5986 100644 --- a/src/common/Constants.py +++ b/src/common/Constants.py @@ -61,6 +61,7 @@ class ServiceNameEnum(Enum): E2EORCHESTRATOR = 'e2eorchestrator' OPTICALCONTROLLER = 'opticalcontroller' BGPLS = 'bgpls-speaker' + APP = 'app' # Used for test and debugging only DLT_GATEWAY = 'dltgateway' @@ -89,6 +90,7 @@ DEFAULT_SERVICE_GRPC_PORTS = { ServiceNameEnum.FORECASTER .value : 10040, ServiceNameEnum.E2EORCHESTRATOR .value : 10050, ServiceNameEnum.OPTICALCONTROLLER .value : 10060, + ServiceNameEnum.APP .value : 10070, ServiceNameEnum.BGPLS .value : 20030, # Used for test and debugging only @@ -101,10 +103,12 @@ DEFAULT_SERVICE_HTTP_PORTS = { ServiceNameEnum.CONTEXT .value : 8080, ServiceNameEnum.NBI .value : 8080, ServiceNameEnum.WEBUI .value : 8004, + ServiceNameEnum.APP .value : 8005, } # Default HTTP/REST-API service base URLs DEFAULT_SERVICE_HTTP_BASEURLS = { ServiceNameEnum.NBI .value : None, ServiceNameEnum.WEBUI .value : None, + ServiceNameEnum.APP .value : None, } diff --git a/src/service/Dockerfile b/src/service/Dockerfile index a847ae762d1303dda852d7f3d8200d3db3ef53f7..cfb9900ae000ef8e542fc9bb4a208b5609057164 100644 --- a/src/service/Dockerfile +++ b/src/service/Dockerfile @@ -70,6 +70,8 @@ COPY src/pathcomp/frontend/__init__.py pathcomp/frontend/__init__.py COPY src/pathcomp/frontend/client/. pathcomp/frontend/client/ COPY src/e2e_orchestrator/__init__.py e2e_orchestrator/__init__.py COPY src/e2e_orchestrator/client/. e2e_orchestrator/client/ +COPY src/app/__init__.py app/__init__.py +COPY src/app/client/. app/client/ COPY src/service/. service/ # Start the service diff --git a/src/service/service/__main__.py b/src/service/service/__main__.py index ae8a9e960cf6a0d720b508fe3ea5592632420c18..9e7e7b46bb2e8bc4242e795250b6162c730951d5 100644 --- a/src/service/service/__main__.py +++ b/src/service/service/__main__.py @@ -44,6 +44,9 @@ 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.APP, ENVVAR_SUFIX_SERVICE_HOST ), + get_env_var_name(ServiceNameEnum.APP, ENVVAR_SUFIX_SERVICE_PORT_GRPC), + ]) signal.signal(signal.SIGINT, signal_handler) @@ -72,4 +75,4 @@ def main(): return 0 if __name__ == '__main__': - sys.exit(main()) + sys.exit(main()) \ No newline at end of file diff --git a/src/service/service/task_scheduler/TaskExecutor.py b/src/service/service/task_scheduler/TaskExecutor.py index cd20faad23a06678be39dbacc476a0ea25d4d540..487fe5b8548bfe1ea3cb1a4b4e9849234ba8de58 100644 --- a/src/service/service/task_scheduler/TaskExecutor.py +++ b/src/service/service/task_scheduler/TaskExecutor.py @@ -20,6 +20,7 @@ from common.proto.context_pb2 import ( Connection, ConnectionId, Device, DeviceDriverEnum, DeviceId, Service, ServiceId, OpticalConfig, OpticalConfigId ) +from common.proto.app_pb2 import App from common.tools.context_queries.Connection import get_connection_by_id from common.tools.context_queries.Device import get_device from common.tools.context_queries.Service import get_service_by_id @@ -27,11 +28,12 @@ from common.tools.grpc.Tools import grpc_message_to_json_string from common.tools.object_factory.Device import json_device_id from context.client.ContextClient import ContextClient from device.client.DeviceClient import DeviceClient +from app.client.AppClient import AppClient from service.service.service_handler_api.Exceptions import ( UnsatisfiedFilterException, UnsupportedFilterFieldException, UnsupportedFilterFieldValueException ) from service.service.service_handler_api.ServiceHandlerFactory import ServiceHandlerFactory, get_service_handler_class -from service.service.tools.ObjectKeys import get_connection_key, get_device_key, get_service_key +from service.service.tools.ObjectKeys import get_connection_key, get_device_key, get_service_key, get_app_key if TYPE_CHECKING: from service.service.service_handler_api._ServiceHandler import _ServiceHandler @@ -44,11 +46,14 @@ class CacheableObjectType(Enum): CONNECTION = 'connection' DEVICE = 'device' SERVICE = 'service' + APP = 'app' class TaskExecutor: def __init__(self, service_handler_factory : ServiceHandlerFactory) -> None: self._service_handler_factory = service_handler_factory self._context_client = ContextClient() + # DEPENDENCY QKD + self._app_client = AppClient() self._device_client = DeviceClient() self._grpc_objects_cache : Dict[str, CacheableObject] = dict() @@ -220,3 +225,12 @@ class TaskExecutor: str(dict_connection_devices) ) ) + + + # ----- App-related methods --------------------------------------------------------------------------------------- + + def register_app(self, app: App) -> None: + app_key = get_app_key(app.app_id) + self._app_client.RegisterApp(app) + LOGGER.info("reg registered") + self._store_grpc_object(CacheableObjectType.APP, app_key, app) \ No newline at end of file diff --git a/src/service/service/tools/ObjectKeys.py b/src/service/service/tools/ObjectKeys.py index f45126e07df6a74a20e507fd51d08f1a32de7f98..50129c704afbd1aff90913b56872d98f6943d39e 100644 --- a/src/service/service/tools/ObjectKeys.py +++ b/src/service/service/tools/ObjectKeys.py @@ -13,6 +13,7 @@ # limitations under the License. from common.proto.context_pb2 import ConnectionId, DeviceId, ServiceId +from common.proto.app_pb2 import AppId def get_connection_key(connection_id : ConnectionId) -> str: return connection_id.connection_uuid.uuid @@ -24,3 +25,7 @@ def get_service_key(service_id : ServiceId) -> str: context_uuid = service_id.context_id.context_uuid.uuid service_uuid = service_id.service_uuid.uuid return '{:s}/{:s}'.format(context_uuid, service_uuid) + +def get_app_key(app_id : AppId) -> str: + return app_id.app_uuid.uuid +