diff --git a/configure_dashboards.sh b/configure_dashboards.sh
index edfdfa370538cfb7129e365be5062f16291a67d7..4a32d76deb79bb514b6d547c0e3e2b87ec269e77 100755
--- a/configure_dashboards.sh
+++ b/configure_dashboards.sh
@@ -25,8 +25,8 @@ INFLUXDB_DATABASE=$(kubectl --namespace $K8S_NAMESPACE get secrets influxdb-secr
 # GRAFANA_HOSTNAME=$(kubectl get node $K8S_HOSTNAME -o 'jsonpath={.status.addresses[?(@.type=="InternalIP")].address}')
 # GRAFANA_HOSTNAME=`kubectl get service/webuiservice-public -n ${K8S_NAMESPACE} -o jsonpath='{.spec.clusterIP}'`
 GRAFANA_HOSTNAME=`kubectl get nodes --selector=node-role.kubernetes.io/master -o jsonpath='{$.items[*].status.addresses[?(@.type=="InternalIP")].address}'`
-# GRAFANA_PORT=$(kubectl get service webuiservice-public --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==3000)].nodePort}')
-GRAFANA_PORT=`kubectl get service/webuiservice-public -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[1].nodePort}'`
+GRAFANA_PORT=$(kubectl get service webuiservice-public --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==3000)].nodePort}')
+#GRAFANA_PORT=`kubectl get service/webuiservice-public -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[1].nodePort}'`
 GRAFANA_USERNAME="admin"
 GRAFANA_PASSWORD=${GRAFANA_PASSWORD:-"admin123+"}
 GRAFANA_URL="http://${GRAFANA_USERNAME}:${GRAFANA_PASSWORD}@${GRAFANA_HOSTNAME}:${GRAFANA_PORT}"
diff --git a/manifests/expose_services.yaml b/manifests/expose_services.yaml
deleted file mode 100644
index 7e5d2236ab3be6928cd9247a8f5a6e8220a4d1ab..0000000000000000000000000000000000000000
--- a/manifests/expose_services.yaml
+++ /dev/null
@@ -1,90 +0,0 @@
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: contextservice-public
-  labels:
-    app: contextservice
-spec:
-  type: NodePort
-  selector:
-    app: contextservice
-  ports:
-  - name: grpc
-    protocol: TCP
-    port: 1010
-    targetPort: 1010
-  - name: http
-    protocol: TCP
-    port: 8080
-    targetPort: 8080
-    nodePort: 30808
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: redis-tests
-  labels:
-    app: contextservice
-spec:
-  type: NodePort
-  selector:
-    app: contextservice
-  ports:
-  - name: redis
-    protocol: TCP
-    port: 6379
-    targetPort: 6379
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: influx-tests
-  labels:
-    app: monitoringservice
-spec:
-  type: NodePort
-  selector:
-    app: monitoringservice
-  ports:
-  - name: influx
-    protocol: TCP
-    port: 8086
-    targetPort: 8086
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: deviceservice-public
-  labels:
-    app: deviceservice
-spec:
-  type: NodePort
-  selector:
-    app: deviceservice
-  ports:
-  - name: grpc
-    protocol: TCP
-    port: 2020
-    targetPort: 2020
----
-apiVersion: v1
-kind: Service
-metadata:
-  name: computeservice-public
-  labels:
-    app: computeservice
-spec:
-  type: NodePort
-  selector:
-    app: computeservice
-  ports:
-  - name: http
-    protocol: TCP
-    port: 8080
-    targetPort: 8080
-  - name: grpc
-    protocol: TCP
-    port: 9090
-    targetPort: 9090
----
\ No newline at end of file
diff --git a/open_dashboard.sh b/open_dashboard.sh
index 6f87b207c24bfd7e61a8d37740ffe104c2dc85a5..8291a22c75cd2c2b83bedcab2ac0167c56c966a6 100755
--- a/open_dashboard.sh
+++ b/open_dashboard.sh
@@ -18,8 +18,8 @@
 
 K8S_NAMESPACE=${K8S_NAMESPACE:-'tf-dev'}
 
-GRAFANA_IP=`kubectl get service/webuiservice -n ${K8S_NAMESPACE} -o jsonpath='{.spec.clusterIP}'`
-GRAFANA_PORT=`kubectl get service/webuiservice -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[1].port}'`
+GRAFANA_IP=$(kubectl get service/webuiservice -n ${K8S_NAMESPACE} -o jsonpath='{.spec.clusterIP}')
+GRAFANA_PORT=$(kubectl get service webuiservice-public --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==3000)].nodePort}')
 URL=http://${GRAFANA_IP}:${GRAFANA_PORT}
 
 echo Opening Dashboard on URL ${URL}
diff --git a/open_webui.sh b/open_webui.sh
index 23cb704ad7a2ee5e9134b2727a02f10b6591582b..f33f7036527c74756564f350924951c19ac4f817 100755
--- a/open_webui.sh
+++ b/open_webui.sh
@@ -16,23 +16,20 @@
 
 K8S_NAMESPACE=${K8S_NAMESPACE:-'tf-dev'}
 
-WEBUI_SERVICE_NAME="service/webuiservice-public"
-WEBUI_PROTO=`kubectl get ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[0].name}'`
-WEBUI_IP=`kubectl get ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.clusterIP}'`
-WEBUI_PORT=`kubectl get ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[0].port}'`
-GRAFANA_PORT=`kubectl get ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[1].port}'`
-URL=${WEBUI_PROTO}://${WEBUI_IP}:${WEBUI_PORT}
+WEBUI_SERVICE_NAME="webuiservice-public"
+WEBUI_PROTO=`kubectl get service ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.ports[0].name}'`
+WEBUI_IP=`kubectl get service ${WEBUI_SERVICE_NAME} -n ${K8S_NAMESPACE} -o jsonpath='{.spec.clusterIP}'`
+WEBUI_PORT=$(kubectl get service ${WEBUI_SERVICE_NAME} --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==8004)].nodePort}')
+GRAFANA_PORT=$(kubectl get service ${WEBUI_SERVICE_NAME} --namespace $K8S_NAMESPACE -o 'jsonpath={.spec.ports[?(@.port==3000)].nodePort}')
 
+# Open WebUI
+URL=${WEBUI_PROTO}://${WEBUI_IP}:${WEBUI_PORT}
 echo Opening web UI on URL ${URL}
-
 # curl -kL ${URL}
-
 python3 -m webbrowser ${URL}
 
+# Open Dashboard
 URL=${WEBUI_PROTO}://${WEBUI_IP}:${GRAFANA_PORT}
-
-echo Opening web UI on URL ${URL}
-
+echo Opening Dashboard on URL ${URL}
 # curl -kL ${URL}
-
 python3 -m webbrowser ${URL}
diff --git a/src/tests/ofc22/.gitignore b/src/tests/ofc22/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..0a3f4400d5c88b1af32c7667d69d2fdc12d5424e
--- /dev/null
+++ b/src/tests/ofc22/.gitignore
@@ -0,0 +1,2 @@
+# Add here your files containing confidential testbed details such as IP addresses, ports, usernames, passwords, etc.
+descriptors_real.json
diff --git a/src/tests/ofc22/descriptors_emulated.json b/src/tests/ofc22/descriptors_emulated.json
new file mode 100644
index 0000000000000000000000000000000000000000..3905fbc59a538185c1baa7d899e48a838864790d
--- /dev/null
+++ b/src/tests/ofc22/descriptors_emulated.json
@@ -0,0 +1,108 @@
+{
+    "contexts": [
+        {
+            "context_id": {"context_uuid": {"uuid": "admin"}},
+            "topology_ids": [],
+            "service_ids": []
+        }
+    ],
+    "topologies": [
+        {
+            "topology_id": {"topology_uuid": {"uuid": "admin"}, "context_id": {"context_uuid": {"uuid": "admin"}}},
+            "device_ids": [],
+            "link_ids": []
+        }
+    ],
+    "devices": [
+        {
+            "device_id": {"device_uuid": {"uuid": "R1-INF"}},
+            "device_type": "emu-packet-router",
+            "device_config": {"config_rules": [
+                {"action": 1, "resource_key": "_connect/address", "resource_value": "127.0.0.1"},
+                {"action": 1, "resource_key": "_connect/port", "resource_value": "0"},
+                {"action": 1, "resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"13/0/0\"}, {\"sample_types\": [101, 102, 201, 202], \"type\": \"copper\", \"uuid\": \"13/1/2\"}]}"}
+            ]},
+            "device_operational_status": 1,
+            "device_drivers": [0],
+            "device_endpoints": []
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R2-EMU"}},
+            "device_type": "emu-packet-router",
+            "device_config": {"config_rules": [
+                {"action": 1, "resource_key": "_connect/address", "resource_value": "127.0.0.1"},
+                {"action": 1, "resource_key": "_connect/port", "resource_value": "0"},
+                {"action": 1, "resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"13/0/0\"}, {\"sample_types\": [101, 102, 201, 202], \"type\": \"copper\", \"uuid\": \"13/1/2\"}]}"}
+            ]},
+            "device_operational_status": 1,
+            "device_drivers": [0],
+            "device_endpoints": []
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R3-INF"}},
+            "device_type": "emu-packet-router",
+            "device_config": {"config_rules": [
+                {"action": 1, "resource_key": "_connect/address", "resource_value": "127.0.0.1"},
+                {"action": 1, "resource_key": "_connect/port", "resource_value": "0"},
+                {"action": 1, "resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"13/0/0\"}, {\"sample_types\": [101, 102, 201, 202], \"type\": \"copper\", \"uuid\": \"13/1/2\"}]}"}
+            ]},
+            "device_operational_status": 1,
+            "device_drivers": [0],
+            "device_endpoints": []
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R4-EMU"}},
+            "device_type": "emu-packet-router",
+            "device_config": {"config_rules": [
+                {"action": 1, "resource_key": "_connect/address", "resource_value": "127.0.0.1"},
+                {"action": 1, "resource_key": "_connect/port", "resource_value": "0"},
+                {"action": 1, "resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"13/0/0\"}, {\"sample_types\": [101, 102, 201, 202], \"type\": \"copper\", \"uuid\": \"13/1/2\"}]}"}
+            ]},
+            "device_operational_status": 1,
+            "device_drivers": [0],
+            "device_endpoints": []
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "O1-OLS"}},
+            "device_type": "emu-optical-line-system",
+            "device_config": {"config_rules": [
+                {"action": 1, "resource_key": "_connect/address", "resource_value": "127.0.0.1"},
+                {"action": 1, "resource_key": "_connect/port", "resource_value": "0"},
+                {"action": 1, "resource_key": "_connect/settings", "resource_value": "{\"endpoints\": [{\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"aade6001-f00b-5e2f-a357-6a0a9d3de870\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"eb287d83-f05e-53ec-ab5a-adf6bd2b5418\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"0ef74f99-1acc-57bd-ab9d-4b958b06c513\"}, {\"sample_types\": [], \"type\": \"optical\", \"uuid\": \"50296d99-58cc-5ce7-82f5-fc8ee4eec2ec\"}]}"}
+            ]},
+            "device_operational_status": 1,
+            "device_drivers": [0],
+            "device_endpoints": []
+        }
+    ],
+    "links": [
+        {
+            "link_id": {"link_uuid": {"uuid": "R1-INF/13/0/0==O1-OLS/aade6001-f00b-5e2f-a357-6a0a9d3de870"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R1-INF"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
+                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "aade6001-f00b-5e2f-a357-6a0a9d3de870"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R2-EMU/13/0/0==O1-OLS/eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R2-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
+                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "eb287d83-f05e-53ec-ab5a-adf6bd2b5418"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R3-INF/13/0/0==O1-OLS/0ef74f99-1acc-57bd-ab9d-4b958b06c513"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R3-INF"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
+                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "0ef74f99-1acc-57bd-ab9d-4b958b06c513"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R4-EMU/13/0/0==O1-OLS/50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R4-EMU"}}, "endpoint_uuid": {"uuid": "13/0/0"}},
+                {"device_id": {"device_uuid": {"uuid": "O1-OLS"}}, "endpoint_uuid": {"uuid": "50296d99-58cc-5ce7-82f5-fc8ee4eec2ec"}}
+            ]
+        }
+    ]
+}
diff --git a/src/tests/ofc22/redeploy_webui.sh b/src/tests/ofc22/redeploy_webui.sh
new file mode 100755
index 0000000000000000000000000000000000000000..975f84a9d3b75e00a809acd336d844973cb26897
--- /dev/null
+++ b/src/tests/ofc22/redeploy_webui.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# 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.
+
+export COMPONENT="webui"
+export IMAGE_TAG="ofc22"
+export K8S_NAMESPACE="ofc22"
+export K8S_HOSTNAME="kubernetes-master"
+export GRAFANA_PASSWORD="admin123+"
+
+# Constants
+TMP_FOLDER="./tmp"
+
+# Create a tmp folder for files modified during the deployment
+TMP_MANIFESTS_FOLDER="$TMP_FOLDER/manifests"
+mkdir -p $TMP_MANIFESTS_FOLDER
+TMP_LOGS_FOLDER="$TMP_FOLDER/logs"
+mkdir -p $TMP_LOGS_FOLDER
+
+echo "Processing '$COMPONENT' component..."
+IMAGE_NAME="$COMPONENT:$IMAGE_TAG"
+
+echo "  Building Docker image..."
+BUILD_LOG="$TMP_LOGS_FOLDER/build_${COMPONENT}.log"
+docker build -t "$IMAGE_NAME" -f ./src/"$COMPONENT"/Dockerfile ./src/ > "$BUILD_LOG"
+
+sleep 1
+
+echo "  Deploying '$COMPONENT' component to Kubernetes..."
+kubectl --namespace $K8S_NAMESPACE scale deployment --replicas=0 ${COMPONENT}service
+kubectl --namespace $K8S_NAMESPACE scale deployment --replicas=1 ${COMPONENT}service
+printf "\n"
+
+sleep 1
+
+echo "Waiting for '$COMPONENT' component..."
+kubectl wait --namespace $K8S_NAMESPACE --for='condition=available' --timeout=300s deployment/${COMPONENT}service
+printf "\n"
+
+echo "Configuring DataStores and Dashboards..."
+./configure_dashboards.sh
+printf "\n\n"
+
+echo "Reporting Deployment..."
+kubectl --namespace $K8S_NAMESPACE get all
+printf "\n"
+
+echo "Done!"
diff --git a/src/tests/ofc22/tests/BuildDescriptors.py b/src/tests/ofc22/tests/BuildDescriptors.py
new file mode 100644
index 0000000000000000000000000000000000000000..5c5419190487eb5089e4a30f523dca43fa3870f2
--- /dev/null
+++ b/src/tests/ofc22/tests/BuildDescriptors.py
@@ -0,0 +1,35 @@
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# 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.
+
+import copy, json, sys
+from .Objects import CONTEXTS, DEVICES, LINKS, TOPOLOGIES
+
+def main():
+    with open('tests/ofc22/descriptors_emulated.json', 'w', encoding='UTF-8') as f:
+        devices = []
+        for device,connect_rules in DEVICES:
+            device = copy.deepcopy(device)
+            device['device_config']['config_rules'].extend(connect_rules)
+            devices.append(device)
+
+        f.write(json.dumps({
+            'contexts': CONTEXTS,
+            'topologies': TOPOLOGIES,
+            'devices': devices,
+            'links': LINKS
+        }))
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/src/tests/ofc22/tests/LoadDescriptors.py b/src/tests/ofc22/tests/LoadDescriptors.py
new file mode 100644
index 0000000000000000000000000000000000000000..c84c2549096f7483699f79de4aaf9b52fb181072
--- /dev/null
+++ b/src/tests/ofc22/tests/LoadDescriptors.py
@@ -0,0 +1,40 @@
+# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+#
+# 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.
+
+import json, logging, sys
+from common.Settings import get_setting
+from context.client.ContextClient import ContextClient
+from context.proto.context_pb2 import Context, ContextId, Device, Empty, Link, Topology
+from device.client.DeviceClient import DeviceClient
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+def main():
+    context_client = ContextClient(
+        get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
+    device_client  = DeviceClient(
+        get_setting('DEVICESERVICE_SERVICE_HOST'), get_setting('DEVICESERVICE_SERVICE_PORT_GRPC'))
+
+    with open('tests/ofc22/descriptors.json', 'r', encoding='UTF-8') as f:
+        descriptors = json.loads(f.read())
+
+    for context  in descriptors['contexts'  ]: context_client.SetContext (Context (**context ))
+    for topology in descriptors['topologies']: context_client.SetTopology(Topology(**topology))
+    for device   in descriptors['devices'   ]: device_client .AddDevice  (Device  (**device  ))
+    for link     in descriptors['links'     ]: context_client.SetLink    (Link    (**link    ))
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/src/tests/ofc22/tests/Objects.py b/src/tests/ofc22/tests/Objects.py
index a47ba7c16d841ca51c9889f83a0796d8540bb621..6205b5e4ada67749f8230e99badca048a2372c2b 100644
--- a/src/tests/ofc22/tests/Objects.py
+++ b/src/tests/ofc22/tests/Objects.py
@@ -61,7 +61,7 @@ except ImportError:
     DEVICE_O1_ADDRESS  = '0.0.0.0'
     DEVICE_O1_PORT     = 4900
 
-# USE_REAL_DEVICES = False     # Uncomment to force to use emulated devices
+#USE_REAL_DEVICES = False     # Uncomment to force to use emulated devices
 
 def json_endpoint_ids(device_id : Dict, endpoint_descriptors : List[Tuple[str, str, List[int]]]):
     return [
diff --git a/src/webui/Config.py b/src/webui/Config.py
index f6fc9125f90e7a78a606129af3b7f55964174ab3..e7720a405e2874c3679f9f507df2fdffc610f84a 100644
--- a/src/webui/Config.py
+++ b/src/webui/Config.py
@@ -25,6 +25,7 @@ WEBUI_SERVICE_PORT = 8004
 METRICS_PORT = 9192
 
 SECRET_KEY = '>s&}24@{]]#k3&^5$f3#?6?h3{W@[}/7z}2pa]>{3&5%RP<)[('
+MAX_CONTENT_LENGTH = 1024*1024
 
 HOST = '0.0.0.0'  # accepts connections coming from any ADDRESS
 
diff --git a/src/webui/service/__main__.py b/src/webui/service/__main__.py
index 38bc0f790d7030ef1ed4ede0085a6161db1f8cec..5dd20aab74751390a11b32e9ae2c63aadb9e364e 100644
--- a/src/webui/service/__main__.py
+++ b/src/webui/service/__main__.py
@@ -16,7 +16,7 @@ import os, sys, logging
 from prometheus_client import start_http_server
 from common.Settings import wait_for_environment_variables
 from webui.service import create_app
-from webui.Config import WEBUI_SERVICE_PORT, LOG_LEVEL, METRICS_PORT, HOST, SECRET_KEY, DEBUG
+from webui.Config import MAX_CONTENT_LENGTH, WEBUI_SERVICE_PORT, LOG_LEVEL, METRICS_PORT, HOST, SECRET_KEY, DEBUG
 
 def main():
     service_port = os.environ.get('WEBUISERVICE_SERVICE_PORT', WEBUI_SERVICE_PORT)
@@ -37,7 +37,10 @@ def main():
 
     start_http_server(metrics_port)
 
-    app = create_app(use_config={'SECRET_KEY': SECRET_KEY})
+    app = create_app(use_config={
+        'SECRET_KEY': SECRET_KEY,
+        'MAX_CONTENT_LENGTH': MAX_CONTENT_LENGTH,
+    })
     app.run(host=host, port=service_port, debug=debug)
 
     logger.info('Bye')
diff --git a/src/webui/service/device/routes.py b/src/webui/service/device/routes.py
index f4e58d3b0f92ef4e002c086ccc6092c9d5d397ef..2221240e5f974dab60e116ee09c81cc9dd41f039 100644
--- a/src/webui/service/device/routes.py
+++ b/src/webui/service/device/routes.py
@@ -17,7 +17,7 @@ from device.client.DeviceClient import DeviceClient
 from context.client.ContextClient import ContextClient
 from webui.Config import (CONTEXT_SERVICE_ADDRESS, CONTEXT_SERVICE_PORT,
                 DEVICE_SERVICE_ADDRESS, DEVICE_SERVICE_PORT)
-from webui.proto.context_pb2 import (ContextId, DeviceList, DeviceId,
+from webui.proto.context_pb2 import (ContextId, DeviceList, DeviceId, Empty,
     Device, DeviceDriverEnum, DeviceOperationalStatusEnum,
     ConfigActionEnum, ConfigRule, TopologyIdList, TopologyList)
 from webui.service.device.forms import AddDeviceForm
@@ -32,10 +32,8 @@ def home():
     if context_uuid == "-":
         flash("Please select a context!", "warning")
         return redirect(url_for("main.home"))
-    request: ContextId = ContextId()
-    request.context_uuid.uuid = session.get('context_uuid', '-')
     context_client.connect()
-    response: DeviceList = context_client.ListDevices(request)
+    response: DeviceList = context_client.ListDevices(Empty())
     context_client.close()
     return render_template('device/home.html', devices=response.devices,
                                                dde=DeviceDriverEnum,
@@ -45,12 +43,6 @@ def home():
 def add():
     form = AddDeviceForm()
 
-    request: ContextId = ContextId()
-    request.context_uuid.uuid = session.get('context_uuid', '-')
-    context_client.connect()
-    response: TopologyIdList = context_client.ListTopologyIds(request)
-    context_client.close()
-
     # listing enum values
     form.operational_status.choices = [(-1, 'Select...')]
     for key, value in DeviceOperationalStatusEnum.DESCRIPTOR.values_by_name.items():
diff --git a/src/webui/service/main/forms.py b/src/webui/service/main/forms.py
index 0dc80c7a20628921b03fc8fd8d0189a75f1053a4..892905e48e7b22bf9c1b27f27cf16f68f8b5aa94 100644
--- a/src/webui/service/main/forms.py
+++ b/src/webui/service/main/forms.py
@@ -14,12 +14,20 @@
 
 # external imports
 from flask_wtf import FlaskForm
-from wtforms import SelectField, SubmitField
-from wtforms.validators import DataRequired, Length
+from flask_wtf.file import FileAllowed
+from wtforms import SelectField, FileField, SubmitField
+#from wtforms.validators import DataRequired, Length
 
 
 class ContextForm(FlaskForm):
-    context = SelectField('Context',
-                           choices=[],
-                           validators=[DataRequired(), Length(min=1)])
-    submit = SubmitField('Select')
+    context = SelectField(  'Context',
+                            choices=[],
+                            validators=[
+                                #DataRequired(),
+                                #Length(min=1)
+                            ])
+    descriptors = FileField('Descriptors',
+                            validators=[
+                                FileAllowed(['json'], 'JSON Descriptors only!')
+                            ])
+    submit = SubmitField('Submit')
diff --git a/src/webui/service/main/routes.py b/src/webui/service/main/routes.py
index 6a74b6f53fdcdd1c46128c695e78a4dab81cf491..81b8fe8c08c85f9ef63ac5df62c7cb9fc042e92c 100644
--- a/src/webui/service/main/routes.py
+++ b/src/webui/service/main/routes.py
@@ -12,38 +12,89 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import logging
 import sys
-from flask import redirect, render_template, Blueprint, flash, session, url_for
-from webui.Config import CONTEXT_SERVICE_ADDRESS, CONTEXT_SERVICE_PORT
+from flask import redirect, render_template, Blueprint, flash, session, url_for, request
+from webui.Config import (CONTEXT_SERVICE_ADDRESS, CONTEXT_SERVICE_PORT,
+                DEVICE_SERVICE_ADDRESS, DEVICE_SERVICE_PORT)
 from context.client.ContextClient import ContextClient
-from webui.proto.context_pb2 import Empty
+from device.client.DeviceClient import DeviceClient
+from webui.proto.context_pb2 import Context, Device, Empty, Link, Topology
 from webui.service.main.forms import ContextForm
 
 main = Blueprint('main', __name__)
 
 context_client: ContextClient = ContextClient(CONTEXT_SERVICE_ADDRESS, CONTEXT_SERVICE_PORT)
+device_client: DeviceClient = DeviceClient(DEVICE_SERVICE_ADDRESS, DEVICE_SERVICE_PORT)
 
 logger = logging.getLogger(__name__)
 
+def process_descriptor(item_name_singluar, item_name_plural, grpc_method, grpc_class, items):
+    num_ok, num_err = 0, 0
+    for item in items:
+        try:
+            grpc_method(grpc_class(**item))
+            num_ok += 1
+        except Exception as e: # pylint: disable=broad-except
+            flash(f'Unable to add {item_name_singluar} {str(item)}: {str(e)}', 'error')
+            num_err += 1
+    if num_ok : flash(f'{str(num_ok)} {item_name_plural} added', 'success')
+    if num_err: flash(f'{str(num_err)} {item_name_plural} failed', 'danger')
+
+def process_descriptors(descriptors):
+    logger.warning(str(descriptors.data))
+    logger.warning(str(descriptors.name))
+    try:
+        logger.warning(str(request.files))
+        descriptors_file = request.files[descriptors.name]
+        logger.warning(str(descriptors_file))
+        descriptors_data = descriptors_file.read()
+        logger.warning(str(descriptors_data))
+        descriptors = json.loads(descriptors_data)
+        logger.warning(str(descriptors))
+    except Exception as e: # pylint: disable=broad-except
+        flash(f'Unable to load descriptor file: {str(e)}', 'danger')
+        return
+
+    process_descriptor('Context',  'Contexts',   context_client.SetContext,  Context,  descriptors['contexts'  ])
+    process_descriptor('Topology', 'Topologies', context_client.SetTopology, Topology, descriptors['topologies'])
+    process_descriptor('Device',   'Devices',    device_client .AddDevice,   Device,   descriptors['devices'   ])
+    process_descriptor('Link',     'Links',      context_client.SetLink,     Link,     descriptors['links'     ])
+
 @main.route('/', methods=['GET', 'POST'])
 def home():
-    # flash('This is an info message', 'info')
-    # flash('This is a danger message', 'danger')
     context_client.connect()
-    response = context_client.ListContextIds(Empty())
-    context_client.close()
-    context_form: ContextForm = ContextForm()
-    context_form.context.choices.append(('', 'Select...'))
-    for context in response.context_ids:
-        context_form.context.choices.append((context.context_uuid.uuid, context.context_uuid))
-    if context_form.validate_on_submit():
-        session['context_uuid'] = context_form.context.data
-        flash(f'The context was successfully set to `{context_form.context.data}`.', 'success')
-    if 'context_uuid' in session:
-        context_form.context.data = session['context_uuid']
-
-    return render_template('main/home.html', context_form=context_form)
+    device_client.connect()
+    try:
+        logger.warning('home: {:s}'.format(str(request)))
+        # flash('This is an info message', 'info')
+        # flash('This is a danger message', 'danger')
+        response = context_client.ListContextIds(Empty())
+        context_form: ContextForm = ContextForm()
+        context_form.context.choices.append(('', 'Select...'))
+        for context in response.context_ids:
+            context_form.context.choices.append((context.context_uuid.uuid, context.context_uuid))
+        logger.warning('context_form.data = {:s}'.format(str(context_form.data)))
+        logger.warning('before validate_on_submit')
+        if context_form.validate_on_submit():
+            logger.warning('inside validate_on_submit')
+            logger.warning('context_form.context.data = {:s}'.format(str(context_form.context.data)))
+            logger.warning('context_form.descriptors.data = {:s}'.format(str(context_form.descriptors.data)))
+            if context_form.context.data:
+                session['context_uuid'] = context_form.context.data
+                flash(f'The context was successfully set to `{context_form.context.data}`.', 'success')
+            if context_form.descriptors.data:
+                process_descriptors(context_form.descriptors)
+        logger.warning('context_form.errors = {:s}'.format(str(context_form.errors)))
+        if 'context_uuid' in session:
+            context_form.context.data = session['context_uuid']
+        return render_template('main/home.html', context_form=context_form)
+    except:
+        logger.exception('Something failed')
+    finally:
+        context_client.close()
+        device_client.close()
 
 
 @main.get('/about')
diff --git a/src/webui/service/templates/main/home.html b/src/webui/service/templates/main/home.html
index e7633bbdbfaf69b5982890045d8e16fe2e795dc8..2a75e19608e6d0ee2c82a945befe37a9dc8abbf7 100644
--- a/src/webui/service/templates/main/home.html
+++ b/src/webui/service/templates/main/home.html
@@ -28,23 +28,43 @@
 
     {% endfor %}
 
-    <h2>Select the working context</h2>
-    <form id="select_context" method="POST">
+    <form id="select_context" method="POST" enctype="multipart/form-data">
         {{ context_form.hidden_tag() }}
         <fieldset class="form-group">
-            <div class="input-group mb-3">
-
-                {% if context_form.context.errors %}
-                    {{ context_form.context(class="form-select is-invalid") }}
-                    <div class="invalid-feedback">
-                        {% for error in context_form.context.errors %}
-                            <span>{{ error }}</span>
-                        {% endfor %}
+            <legend>Select the working context, or upload a JSON descriptors file</legend>
+            <div class="row mb-3">
+                <div class="row mb-3">
+                    {{ context_form.context.label(class="col-sm-2 col-form-label") }}
+                    <div class="col-sm-10">
+                        {% if context_form.context.errors %}
+                            {{ context_form.context(class="form-select is-invalid") }}
+                            <div class="invalid-feedback">
+                                {% for error in context_form.context.errors %}
+                                    <span>{{ error }}</span>
+                                {% endfor %}
+                            </div>
+                        {% else %}
+                            {{ context_form.context(class="form-select") }}
+                        {% endif %}
                     </div>
-                {% else %}
-                    {{ context_form.context(class="form-select") }}
-                {% endif %}
+                </div>
 
+                {{ context_form.descriptors.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if context_form.descriptors.errors %}
+                        {{ context_form.descriptors(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in context_form.descriptors.errors %}
+                                <span>{{ error }}</span>
+                            {% endfor %}
+                        </div>
+                    {% else %}
+                        {{ context_form.descriptors(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+
+            <div class="d-grid gap-2 d-md-flex justify-content-md-start">
                 {{ context_form.submit(class='btn btn-primary') }}
             </div>
         </fieldset>