diff --git a/deploy/tfs.sh b/deploy/tfs.sh
index facba7cfd85abfc6a615528d837c37e09406f9d5..fd8625cf2563280e8e6a8ff7a714a03a8622a473 100755
--- a/deploy/tfs.sh
+++ b/deploy/tfs.sh
@@ -428,7 +428,7 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]]; then
     curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{
         "access"   : "proxy",
         "type"     : "prometheus",
-        "name"     : "Prometheus",
+        "name"     : "prometheus",
         "url"      : "http://prometheus-k8s.monitoring.svc:9090",
         "basicAuth": false,
         "isDefault": false,
@@ -438,23 +438,68 @@ if [[ "$TFS_COMPONENTS" == *"webui"* ]]; then
     }' ${GRAFANA_URL_UPDATED}/api/datasources
     printf "\n\n"
 
-    echo ">> Creating dashboards..."
+    echo ">> Creating and staring dashboards..."
     # Ref: https://grafana.com/docs/grafana/latest/http_api/dashboard/
+
+    # Dashboard: L3 Monitoring KPIs
     curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_db_mon_kpis_psql.json' \
         ${GRAFANA_URL_UPDATED}/api/dashboards/db
     echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-l3-monit"
+    DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
+    curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
+    echo
 
+    # Dashboard: Slice Grouping
     curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_db_slc_grps_psql.json' \
         ${GRAFANA_URL_UPDATED}/api/dashboards/db
-    printf "\n\n"
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-slice-grps"
+    DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
+    curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
+    echo
 
-    echo ">> Staring dashboards..."
-    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-l3-monit"
+    # Dashboard: Component RPCs
+    curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_prom_component_rpc.json' \
+        ${GRAFANA_URL_UPDATED}/api/dashboards/db
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-comp-rpc"
     DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
     curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
     echo
 
-    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-slice-grps"
+    # Dashboard: Device Drivers
+    curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_prom_device_driver.json' \
+        ${GRAFANA_URL_UPDATED}/api/dashboards/db
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-dev-drv"
+    DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
+    curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
+    echo
+
+    # Dashboard: Service Handlers
+    curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_prom_service_handler.json' \
+        ${GRAFANA_URL_UPDATED}/api/dashboards/db
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-svc-hdlr"
+    DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
+    curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
+    echo
+
+    # Dashboard: Device Execution Details
+    curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_prom_device_exec_details.json' \
+        ${GRAFANA_URL_UPDATED}/api/dashboards/db
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-dev-exec"
+    DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
+    curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
+    echo
+
+    # Dashboard: Load Generator Status
+    curl -X POST -H "Content-Type: application/json" -d '@src/webui/grafana_prom_load_generator.json' \
+        ${GRAFANA_URL_UPDATED}/api/dashboards/db
+    echo
+    DASHBOARD_URL="${GRAFANA_URL_UPDATED}/api/dashboards/uid/tfs-loadgen-stats"
     DASHBOARD_ID=$(curl -s "${DASHBOARD_URL}" | jq '.dashboard.id')
     curl -X POST ${GRAFANA_URL_UPDATED}/api/user/stars/dashboard/${DASHBOARD_ID}
     echo
diff --git a/manifests/cockroachdb/client-secure-operator.yaml b/manifests/cockroachdb/client-secure-operator.yaml
index f7f81c8339d4ba47722a0ef2a2236178f1b9e1b0..ee3afbc5ae5feec673dc5f507f8bc794757818c7 100644
--- a/manifests/cockroachdb/client-secure-operator.yaml
+++ b/manifests/cockroachdb/client-secure-operator.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 The Cockroach Authors
+# Copyright 2023 The Cockroach Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ spec:
   serviceAccountName: cockroachdb-sa
   containers:
   - name: cockroachdb-client-secure
-    image: cockroachdb/cockroach:v22.2.0
+    image: cockroachdb/cockroach:v22.2.8
     imagePullPolicy: IfNotPresent
     volumeMounts:
     - name: client-certs
diff --git a/manifests/cockroachdb/cluster.yaml b/manifests/cockroachdb/cluster.yaml
index b618c6f17c2e00b9ff74509955b060c67ea3d2cc..4d9ef0f844b5ffb02753b6cc7a7be7d03928896c 100644
--- a/manifests/cockroachdb/cluster.yaml
+++ b/manifests/cockroachdb/cluster.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 The Cockroach Authors
+# Copyright 2023 The Cockroach Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -33,17 +33,16 @@ spec:
   resources:
     requests:
       # This is intentionally low to make it work on local k3d clusters.
-      cpu: 100m
-      memory: 1Gi
-    limits:
-      cpu: 1
+      cpu: 4
       memory: 4Gi
+    limits:
+      cpu: 8
+      memory: 8Gi
   tlsEnabled: true
 # You can set either a version of the db or a specific image name
-# cockroachDBVersion: v22.2.0
+# cockroachDBVersion: v22.2.8
   image:
-    #name: cockroachdb/cockroach:v22.2.0
-    name: cockroachdb/cockroach:latest-v22.2
+    name: cockroachdb/cockroach:v22.2.8
   # nodes refers to the number of crdb pods that are created
   # via the statefulset
   nodes: 3
diff --git a/manifests/cockroachdb/crds.yaml b/manifests/cockroachdb/crds.yaml
index 1b5cd89ae7001b3e200c0de7da240b660c461f3b..2ef9983924f639a82d2091907384be18e6c8c1f4 100644
--- a/manifests/cockroachdb/crds.yaml
+++ b/manifests/cockroachdb/crds.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 The Cockroach Authors
+# Copyright 2023 The Cockroach Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -354,10 +354,71 @@ spec:
                                         The requirements are ANDed.
                                       type: object
                                   type: object
+                                namespaceSelector:
+                                  description: A label query over the set of namespaces
+                                    that the term applies to. The term is applied
+                                    to the union of the namespaces selected by this
+                                    field and the ones listed in the namespaces field.
+                                    null selector and null or empty namespaces list
+                                    means "this pod's namespace". An empty selector
+                                    ({}) matches all namespaces. This field is alpha-level
+                                    and is only honored when PodAffinityNamespaceSelector
+                                    feature is enabled.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list of label
+                                        selector requirements. The requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector requirement
+                                          is a selector that contains values, a key,
+                                          and an operator that relates the key and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a key's
+                                              relationship to a set of values. Valid
+                                              operators are In, NotIn, Exists and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of string
+                                              values. If the operator is In or NotIn,
+                                              the values array must be non-empty.
+                                              If the operator is Exists or DoesNotExist,
+                                              the values array must be empty. This
+                                              array is replaced during a strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of {key,value}
+                                        pairs. A single {key,value} in the matchLabels
+                                        map is equivalent to an element of matchExpressions,
+                                        whose key field is "key", the operator is
+                                        "In", and the values array contains only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
                                 namespaces:
-                                  description: namespaces specifies which namespaces
-                                    the labelSelector applies to (matches against);
-                                    null or empty list means "this pod's namespace"
+                                  description: namespaces specifies a static list
+                                    of namespace names that the term applies to. The
+                                    term is applied to the union of the namespaces
+                                    listed in this field and the ones selected by
+                                    namespaceSelector. null or empty namespaces list
+                                    and null namespaceSelector means "this pod's namespace"
                                   items:
                                     type: string
                                   type: array
@@ -449,10 +510,66 @@ spec:
                                     requirements are ANDed.
                                   type: object
                               type: object
+                            namespaceSelector:
+                              description: A label query over the set of namespaces
+                                that the term applies to. The term is applied to the
+                                union of the namespaces selected by this field and
+                                the ones listed in the namespaces field. null selector
+                                and null or empty namespaces list means "this pod's
+                                namespace". An empty selector ({}) matches all namespaces.
+                                This field is alpha-level and is only honored when
+                                PodAffinityNamespaceSelector feature is enabled.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of label
+                                    selector requirements. The requirements are ANDed.
+                                  items:
+                                    description: A label selector requirement is a
+                                      selector that contains values, a key, and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a key's relationship
+                                          to a set of values. Valid operators are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of string
+                                          values. If the operator is In or NotIn,
+                                          the values array must be non-empty. If the
+                                          operator is Exists or DoesNotExist, the
+                                          values array must be empty. This array is
+                                          replaced during a strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of {key,value}
+                                    pairs. A single {key,value} in the matchLabels
+                                    map is equivalent to an element of matchExpressions,
+                                    whose key field is "key", the operator is "In",
+                                    and the values array contains only "value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
                             namespaces:
-                              description: namespaces specifies which namespaces the
-                                labelSelector applies to (matches against); null or
-                                empty list means "this pod's namespace"
+                              description: namespaces specifies a static list of namespace
+                                names that the term applies to. The term is applied
+                                to the union of the namespaces listed in this field
+                                and the ones selected by namespaceSelector. null or
+                                empty namespaces list and null namespaceSelector means
+                                "this pod's namespace"
                               items:
                                 type: string
                               type: array
@@ -546,10 +663,71 @@ spec:
                                         The requirements are ANDed.
                                       type: object
                                   type: object
+                                namespaceSelector:
+                                  description: A label query over the set of namespaces
+                                    that the term applies to. The term is applied
+                                    to the union of the namespaces selected by this
+                                    field and the ones listed in the namespaces field.
+                                    null selector and null or empty namespaces list
+                                    means "this pod's namespace". An empty selector
+                                    ({}) matches all namespaces. This field is alpha-level
+                                    and is only honored when PodAffinityNamespaceSelector
+                                    feature is enabled.
+                                  properties:
+                                    matchExpressions:
+                                      description: matchExpressions is a list of label
+                                        selector requirements. The requirements are
+                                        ANDed.
+                                      items:
+                                        description: A label selector requirement
+                                          is a selector that contains values, a key,
+                                          and an operator that relates the key and
+                                          values.
+                                        properties:
+                                          key:
+                                            description: key is the label key that
+                                              the selector applies to.
+                                            type: string
+                                          operator:
+                                            description: operator represents a key's
+                                              relationship to a set of values. Valid
+                                              operators are In, NotIn, Exists and
+                                              DoesNotExist.
+                                            type: string
+                                          values:
+                                            description: values is an array of string
+                                              values. If the operator is In or NotIn,
+                                              the values array must be non-empty.
+                                              If the operator is Exists or DoesNotExist,
+                                              the values array must be empty. This
+                                              array is replaced during a strategic
+                                              merge patch.
+                                            items:
+                                              type: string
+                                            type: array
+                                        required:
+                                        - key
+                                        - operator
+                                        type: object
+                                      type: array
+                                    matchLabels:
+                                      additionalProperties:
+                                        type: string
+                                      description: matchLabels is a map of {key,value}
+                                        pairs. A single {key,value} in the matchLabels
+                                        map is equivalent to an element of matchExpressions,
+                                        whose key field is "key", the operator is
+                                        "In", and the values array contains only "value".
+                                        The requirements are ANDed.
+                                      type: object
+                                  type: object
                                 namespaces:
-                                  description: namespaces specifies which namespaces
-                                    the labelSelector applies to (matches against);
-                                    null or empty list means "this pod's namespace"
+                                  description: namespaces specifies a static list
+                                    of namespace names that the term applies to. The
+                                    term is applied to the union of the namespaces
+                                    listed in this field and the ones selected by
+                                    namespaceSelector. null or empty namespaces list
+                                    and null namespaceSelector means "this pod's namespace"
                                   items:
                                     type: string
                                   type: array
@@ -641,10 +819,66 @@ spec:
                                     requirements are ANDed.
                                   type: object
                               type: object
+                            namespaceSelector:
+                              description: A label query over the set of namespaces
+                                that the term applies to. The term is applied to the
+                                union of the namespaces selected by this field and
+                                the ones listed in the namespaces field. null selector
+                                and null or empty namespaces list means "this pod's
+                                namespace". An empty selector ({}) matches all namespaces.
+                                This field is alpha-level and is only honored when
+                                PodAffinityNamespaceSelector feature is enabled.
+                              properties:
+                                matchExpressions:
+                                  description: matchExpressions is a list of label
+                                    selector requirements. The requirements are ANDed.
+                                  items:
+                                    description: A label selector requirement is a
+                                      selector that contains values, a key, and an
+                                      operator that relates the key and values.
+                                    properties:
+                                      key:
+                                        description: key is the label key that the
+                                          selector applies to.
+                                        type: string
+                                      operator:
+                                        description: operator represents a key's relationship
+                                          to a set of values. Valid operators are
+                                          In, NotIn, Exists and DoesNotExist.
+                                        type: string
+                                      values:
+                                        description: values is an array of string
+                                          values. If the operator is In or NotIn,
+                                          the values array must be non-empty. If the
+                                          operator is Exists or DoesNotExist, the
+                                          values array must be empty. This array is
+                                          replaced during a strategic merge patch.
+                                        items:
+                                          type: string
+                                        type: array
+                                    required:
+                                    - key
+                                    - operator
+                                    type: object
+                                  type: array
+                                matchLabels:
+                                  additionalProperties:
+                                    type: string
+                                  description: matchLabels is a map of {key,value}
+                                    pairs. A single {key,value} in the matchLabels
+                                    map is equivalent to an element of matchExpressions,
+                                    whose key field is "key", the operator is "In",
+                                    and the values array contains only "value". The
+                                    requirements are ANDed.
+                                  type: object
+                              type: object
                             namespaces:
-                              description: namespaces specifies which namespaces the
-                                labelSelector applies to (matches against); null or
-                                empty list means "this pod's namespace"
+                              description: namespaces specifies a static list of namespace
+                                names that the term applies to. The term is applied
+                                to the union of the namespaces listed in this field
+                                and the ones selected by namespaceSelector. null or
+                                empty namespaces list and null namespaceSelector means
+                                "this pod's namespace"
                               items:
                                 type: string
                               type: array
@@ -767,7 +1001,7 @@ spec:
                                   pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                                   x-kubernetes-int-or-string: true
                                 description: 'Limits describes the maximum amount
-                                  of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                                  of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                                 type: object
                               requests:
                                 additionalProperties:
@@ -780,7 +1014,7 @@ spec:
                                   of compute resources required. If Requests is omitted
                                   for a container, it defaults to Limits if that is
                                   explicitly specified, otherwise to an implementation-defined
-                                  value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                                  value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                                 type: object
                             type: object
                           selector:
@@ -1138,7 +1372,7 @@ spec:
                       pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
                       x-kubernetes-int-or-string: true
                     description: 'Limits describes the maximum amount of compute resources
-                      allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                      allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                     type: object
                   requests:
                     additionalProperties:
@@ -1150,7 +1384,7 @@ spec:
                     description: 'Requests describes the minimum amount of compute
                       resources required. If Requests is omitted for a container,
                       it defaults to Limits if that is explicitly specified, otherwise
-                      to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/'
+                      to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
                     type: object
                 type: object
               sqlPort:
diff --git a/manifests/cockroachdb/operator.yaml b/manifests/cockroachdb/operator.yaml
index 2be72d329b48bc6f45d66f811c299140cda85e27..59d515061c4c0f253523aab803653b3f33007461 100644
--- a/manifests/cockroachdb/operator.yaml
+++ b/manifests/cockroachdb/operator.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 The Cockroach Authors
+# Copyright 2023 The Cockroach Authors
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -538,8 +538,34 @@ spec:
           value: cockroachdb/cockroach:v22.1.11
         - name: RELATED_IMAGE_COCKROACH_v22_1_12
           value: cockroachdb/cockroach:v22.1.12
+        - name: RELATED_IMAGE_COCKROACH_v22_1_13
+          value: cockroachdb/cockroach:v22.1.13
+        - name: RELATED_IMAGE_COCKROACH_v22_1_14
+          value: cockroachdb/cockroach:v22.1.14
+        - name: RELATED_IMAGE_COCKROACH_v22_1_15
+          value: cockroachdb/cockroach:v22.1.15
+        - name: RELATED_IMAGE_COCKROACH_v22_1_16
+          value: cockroachdb/cockroach:v22.1.16
+        - name: RELATED_IMAGE_COCKROACH_v22_1_18
+          value: cockroachdb/cockroach:v22.1.18
         - name: RELATED_IMAGE_COCKROACH_v22_2_0
           value: cockroachdb/cockroach:v22.2.0
+        - name: RELATED_IMAGE_COCKROACH_v22_2_1
+          value: cockroachdb/cockroach:v22.2.1
+        - name: RELATED_IMAGE_COCKROACH_v22_2_2
+          value: cockroachdb/cockroach:v22.2.2
+        - name: RELATED_IMAGE_COCKROACH_v22_2_3
+          value: cockroachdb/cockroach:v22.2.3
+        - name: RELATED_IMAGE_COCKROACH_v22_2_4
+          value: cockroachdb/cockroach:v22.2.4
+        - name: RELATED_IMAGE_COCKROACH_v22_2_5
+          value: cockroachdb/cockroach:v22.2.5
+        - name: RELATED_IMAGE_COCKROACH_v22_2_6
+          value: cockroachdb/cockroach:v22.2.6
+        - name: RELATED_IMAGE_COCKROACH_v22_2_7
+          value: cockroachdb/cockroach:v22.2.7
+        - name: RELATED_IMAGE_COCKROACH_v22_2_8
+          value: cockroachdb/cockroach:v22.2.8
         - name: OPERATOR_NAME
           value: cockroachdb
         - name: WATCH_NAMESPACE
@@ -552,7 +578,7 @@ spec:
           valueFrom:
             fieldRef:
               fieldPath: metadata.namespace
-        image: cockroachdb/cockroach-operator:v2.9.0
+        image: cockroachdb/cockroach-operator:v2.10.0
         imagePullPolicy: IfNotPresent
         name: cockroach-operator
         resources:
diff --git a/manifests/load_generatorservice.yaml b/manifests/load_generatorservice.yaml
index 3f65c2c857a39f2b7a5ebeaccd9ddfd4916f2487..7cc6f19122573a612ddca774c3a785bff93f8b38 100644
--- a/manifests/load_generatorservice.yaml
+++ b/manifests/load_generatorservice.yaml
@@ -33,6 +33,7 @@ spec:
         imagePullPolicy: Always
         ports:
         - containerPort: 50052
+        - containerPort: 9192
         env:
         - name: LOG_LEVEL
           value: "INFO"
@@ -65,3 +66,7 @@ spec:
     protocol: TCP
     port: 50052
     targetPort: 50052
+  - name: metrics
+    protocol: TCP
+    port: 9192
+    targetPort: 9192
diff --git a/manifests/servicemonitors.yaml b/manifests/servicemonitors.yaml
index f5da08182a4665b21607987ea97d9bf3cc5b7e21..ec929f757cdf5468a7db7a7c1f1e755611d5327b 100644
--- a/manifests/servicemonitors.yaml
+++ b/manifests/servicemonitors.yaml
@@ -330,3 +330,32 @@ spec:
     any: false
     matchNames:
     - tfs # namespace where the app is running
+---
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+  namespace: monitoring # namespace where prometheus is running
+  name: tfs-load-generatorservice-metric
+  labels:
+    app: load-generatorservice
+    #release: prometheus
+    #release: prom  # name of the release 
+    # ( VERY IMPORTANT: You need to know the correct release name by viewing 
+    #   the servicemonitor of Prometheus itself: Without the correct name, 
+    #   Prometheus cannot identify the metrics of the Flask app as the target.)
+spec:
+  selector:
+    matchLabels:
+      # Target app service
+      #namespace: tfs
+      app: load-generatorservice # same as above
+      #release: prometheus # same as above
+  endpoints:
+  - port: metrics # named port in target app
+    scheme: http
+    path: /metrics # path to scrape
+    interval: 5s # scrape interval
+  namespaceSelector:
+    any: false
+    matchNames:
+    - tfs # namespace where the app is running
diff --git a/proto/load_generator.proto b/proto/load_generator.proto
index 86f9469588f1586da5339edad198e39e82598cde..32523b331418813b51fb542d9eb17e29fc2b13d2 100644
--- a/proto/load_generator.proto
+++ b/proto/load_generator.proto
@@ -33,21 +33,40 @@ enum RequestTypeEnum {
   REQUESTTYPE_SLICE_L3NM   = 6;
 }
 
+message Range {
+  float minimum = 1;
+  float maximum = 2;
+}
+
+message ScalarOrRange {
+  oneof value {
+    float scalar = 1; // select the scalar value
+    Range range = 2;  // select a random uniformly dstributed value between minimum and maximum
+  }
+}
+
 message Parameters {
   uint64 num_requests = 1;  // if == 0, generate infinite requests
   repeated RequestTypeEnum request_types = 2;
-  float offered_load = 3;
-  float holding_time = 4;
-  float inter_arrival_time = 5;
-  bool do_teardown = 6;
-  bool dry_mode = 7;
-  bool record_to_dlt = 8;
-  string dlt_domain_id = 9;
+  string device_regex = 3;      // Only devices and endpoints matching the regex expression will be considered as
+  string endpoint_regex = 4;    // source-destination candidates for the requests generated.
+  float offered_load = 5;
+  float holding_time = 6;
+  float inter_arrival_time = 7;
+  repeated ScalarOrRange availability = 8;    // One from the list is selected to populate the constraint
+  repeated ScalarOrRange capacity_gbps = 9;   // One from the list is selected to populate the constraint
+  repeated ScalarOrRange e2e_latency_ms = 10; // One from the list is selected to populate the constraint
+  uint32 max_workers = 11;
+  bool do_teardown = 12;
+  bool dry_mode = 13;
+  bool record_to_dlt = 14;
+  string dlt_domain_id = 15;
 }
 
 message Status {
   Parameters parameters = 1;
   uint64 num_generated = 2;
-  bool infinite_loop = 3;
-  bool running = 4;
+  uint64 num_released = 3;
+  bool infinite_loop = 4;
+  bool running = 5;
 }
diff --git a/src/common/method_wrappers/Decorator.py b/src/common/method_wrappers/Decorator.py
index a5db54125518933199c27662bc0c044988d1daac..b241d3b62821c0bfe319546cbeadce79fce59db9 100644
--- a/src/common/method_wrappers/Decorator.py
+++ b/src/common/method_wrappers/Decorator.py
@@ -15,7 +15,7 @@
 import grpc, json, logging, threading
 from enum import Enum
 from prettytable import PrettyTable
-from typing import Any, Dict, List, Set, Tuple
+from typing import Any, Dict, List, Optional, Set, Tuple
 from prometheus_client import Counter, Histogram
 from prometheus_client.metrics import MetricWrapperBase, INF
 from common.tools.grpc.Tools import grpc_message_to_json_string
@@ -25,12 +25,14 @@ class MetricTypeEnum(Enum):
     COUNTER_STARTED    = 'tfs_{component:s}_{sub_module:s}_{method:s}_counter_requests_started'
     COUNTER_COMPLETED  = 'tfs_{component:s}_{sub_module:s}_{method:s}_counter_requests_completed'
     COUNTER_FAILED     = 'tfs_{component:s}_{sub_module:s}_{method:s}_counter_requests_failed'
+    COUNTER_BLOCKED    = 'tfs_{component:s}_{sub_module:s}_{method:s}_counter_requests_blocked'
     HISTOGRAM_DURATION = 'tfs_{component:s}_{sub_module:s}_{method:s}_histogram_duration'
 
 METRIC_TO_CLASS_PARAMS = {
     MetricTypeEnum.COUNTER_STARTED   : (Counter,   {}),
     MetricTypeEnum.COUNTER_COMPLETED : (Counter,   {}),
     MetricTypeEnum.COUNTER_FAILED    : (Counter,   {}),
+    MetricTypeEnum.COUNTER_BLOCKED   : (Counter,   {}),
     MetricTypeEnum.HISTOGRAM_DURATION: (Histogram, {
         'buckets': (
             # .005, .01, .025, .05, .075, .1, .25, .5, .75, 1.0, INF
@@ -75,21 +77,45 @@ class MetricsPool:
             return MetricsPool.metrics[metric_name]
 
     def get_metrics(
-        self, method : str
-    ) -> Tuple[MetricWrapperBase, MetricWrapperBase, MetricWrapperBase, MetricWrapperBase]:
+        self, method : str, labels : Optional[Dict[str, str]] = None
+    ) -> Tuple[Histogram, Counter, Counter, Counter]:
         histogram_duration : Histogram = self.get_or_create(method, MetricTypeEnum.HISTOGRAM_DURATION)
         counter_started    : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_STARTED)
         counter_completed  : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_COMPLETED)
         counter_failed     : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_FAILED)
 
-        if len(self._labels) > 0:
-            histogram_duration = histogram_duration.labels(**(self._labels))
-            counter_started    = counter_started.labels(**(self._labels))
-            counter_completed  = counter_completed.labels(**(self._labels))
-            counter_failed     = counter_failed.labels(**(self._labels))
+        if labels is None and len(self._labels) > 0:
+            labels = self._labels
+
+        if labels is not None and len(labels) > 0:
+            histogram_duration = histogram_duration.labels(**labels)
+            counter_started    = counter_started.labels(**labels)
+            counter_completed  = counter_completed.labels(**labels)
+            counter_failed     = counter_failed.labels(**labels)
 
         return histogram_duration, counter_started, counter_completed, counter_failed
 
+    def get_metrics_loadgen(
+        self, method : str, labels : Optional[Dict[str, str]] = None
+    ) -> Tuple[Histogram, Counter, Counter, Counter, Counter]:
+        histogram_duration : Histogram = self.get_or_create(method, MetricTypeEnum.HISTOGRAM_DURATION)
+        counter_started    : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_STARTED)
+        counter_completed  : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_COMPLETED)
+        counter_failed     : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_FAILED)
+        counter_blocked    : Counter   = self.get_or_create(method, MetricTypeEnum.COUNTER_BLOCKED)
+
+        if labels is None and len(self._labels) > 0:
+            labels = self._labels
+
+        if labels is not None and len(labels) > 0:
+            histogram_duration = histogram_duration.labels(**labels)
+            counter_started    = counter_started.labels(**labels)
+            counter_completed  = counter_completed.labels(**labels)
+            counter_failed     = counter_failed.labels(**labels)
+            counter_blocked    = counter_blocked.labels(**labels)
+
+        return histogram_duration, counter_started, counter_completed, counter_failed, counter_blocked
+
     def get_pretty_table(self, remove_empty_buckets : bool = True) -> PrettyTable:
         with MetricsPool.lock:
             method_to_metric_fields : Dict[str, Dict[str, Dict[str, Any]]] = dict()
@@ -200,6 +226,8 @@ def safe_and_metered_rpc_method(metrics_pool : MetricsPool, logger : logging.Log
                     # Assume not found or already exists is just a condition, not an error
                     logger.exception('{:s} exception'.format(method_name))
                     counter_failed.inc()
+                else:
+                    counter_completed.inc()
                 grpc_context.abort(e.code, e.details)
             except Exception as e:          # pragma: no cover, pylint: disable=broad-except
                 logger.exception('{:s} exception'.format(method_name))
diff --git a/src/common/method_wrappers/tests/grafana_prometheus_component_rpc.json b/src/common/method_wrappers/tests/grafana_prometheus_component_rpc.json
deleted file mode 100644
index b5b857e7573264f26289ba9a72ec5444e4ac71a4..0000000000000000000000000000000000000000
--- a/src/common/method_wrappers/tests/grafana_prometheus_component_rpc.json
+++ /dev/null
@@ -1,426 +0,0 @@
-{
-  "annotations": {
-    "list": [
-      {
-        "builtIn": 1,
-        "datasource": "-- Grafana --",
-        "enable": true,
-        "hide": true,
-        "iconColor": "rgba(0, 211, 255, 1)",
-        "name": "Annotations & Alerts",
-        "type": "dashboard"
-      }
-    ]
-  },
-  "editable": true,
-  "gnetId": null,
-  "graphTooltip": 0,
-  "id": 25,
-  "iteration": 1671297223428,
-  "links": [],
-  "panels": [
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 0
-      },
-      "hiddenSeries": false,
-      "id": 4,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_started_total{pod=~\"[[pod]]\"})",
-          "interval": "",
-          "legendFormat": "started",
-          "queryType": "randomWalk",
-          "refId": "A"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_completed_total{pod=~\"[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "completed",
-          "refId": "B"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_started_total{pod=~\"[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "failed",
-          "refId": "C"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Requests",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:935",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:936",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    },
-    {
-      "cards": {
-        "cardPadding": null,
-        "cardRound": null
-      },
-      "color": {
-        "cardColor": "#b4ff00",
-        "colorScale": "linear",
-        "colorScheme": "interpolateRdYlGn",
-        "exponent": 0.5,
-        "max": null,
-        "min": 0,
-        "mode": "opacity"
-      },
-      "dataFormat": "tsbuckets",
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "gridPos": {
-        "h": 8,
-        "w": 24,
-        "x": 0,
-        "y": 6
-      },
-      "heatmap": {},
-      "hideZeroBuckets": true,
-      "highlightCards": true,
-      "id": 2,
-      "interval": "60s",
-      "legend": {
-        "show": true
-      },
-      "pluginVersion": "7.5.4",
-      "reverseYBuckets": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(\r\n    max_over_time(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m])\r\n) by (le)",
-          "format": "heatmap",
-          "instant": false,
-          "interval": "1m",
-          "intervalFactor": 1,
-          "legendFormat": "{{le}}",
-          "queryType": "randomWalk",
-          "refId": "A"
-        }
-      ],
-      "title": "Histogram",
-      "tooltip": {
-        "show": true,
-        "showHistogram": true
-      },
-      "type": "heatmap",
-      "xAxis": {
-        "show": true
-      },
-      "xBucketNumber": null,
-      "xBucketSize": null,
-      "yAxis": {
-        "decimals": null,
-        "format": "s",
-        "logBase": 1,
-        "max": null,
-        "min": null,
-        "show": true,
-        "splitFactor": null
-      },
-      "yBucketBound": "auto",
-      "yBucketNumber": null,
-      "yBucketSize": null
-    },
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 14
-      },
-      "hiddenSeries": false,
-      "id": 5,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_[[component]]_rpc_[[method]]_histogram_duration_sum{pod=~\"[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "total time",
-          "refId": "B"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Total Exec Time",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:407",
-          "format": "s",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:408",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    }
-  ],
-  "refresh": "5s",
-  "schemaVersion": 27,
-  "style": "dark",
-  "tags": [],
-  "templating": {
-    "list": [
-      {
-        "allValue": null,
-        "current": {
-          "selected": false,
-          "text": "context",
-          "value": "context"
-        },
-        "datasource": "prometheus",
-        "definition": "metrics(tfs_)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": false,
-        "label": "Component",
-        "multi": false,
-        "name": "component",
-        "options": [],
-        "query": {
-          "query": "metrics(tfs_)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/tfs_(.+)_rpc_.*/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": "",
-        "current": {
-          "selected": false,
-          "text": "getcontext",
-          "value": "getcontext"
-        },
-        "datasource": "prometheus",
-        "definition": "metrics(tfs_[[component]]_rpc_)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": false,
-        "label": "Method",
-        "multi": false,
-        "name": "method",
-        "options": [],
-        "query": {
-          "query": "metrics(tfs_[[component]]_rpc_)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/tfs_[[component]]_rpc_(.+)_histogram_duration_bucket/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket, pod)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Pod",
-        "multi": true,
-        "name": "pod",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket, pod)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      }
-    ]
-  },
-  "time": {
-    "from": "now-15m",
-    "to": "now"
-  },
-  "timepicker": {},
-  "timezone": "",
-  "title": "TFS / Component RPCs",
-  "uid": "KKxzxIFVz",
-  "version": 21
-}
\ No newline at end of file
diff --git a/src/common/method_wrappers/tests/grafana_prometheus_device_config_exec_details.json b/src/common/method_wrappers/tests/grafana_prometheus_device_config_exec_details.json
deleted file mode 100644
index 980b9583a898f8fb2d84c22329ce8053e120b7f8..0000000000000000000000000000000000000000
--- a/src/common/method_wrappers/tests/grafana_prometheus_device_config_exec_details.json
+++ /dev/null
@@ -1,185 +0,0 @@
-{
-  "annotations": {
-    "list": [
-      {
-        "builtIn": 1,
-        "datasource": "-- Grafana --",
-        "enable": true,
-        "hide": true,
-        "iconColor": "rgba(0, 211, 255, 1)",
-        "name": "Annotations & Alerts",
-        "type": "dashboard"
-      }
-    ]
-  },
-  "editable": true,
-  "gnetId": null,
-  "graphTooltip": 0,
-  "id": 30,
-  "iteration": 1682003744753,
-  "links": [],
-  "panels": [
-    {
-      "cards": {
-        "cardPadding": null,
-        "cardRound": null
-      },
-      "color": {
-        "cardColor": "#b4ff00",
-        "colorScale": "linear",
-        "colorScheme": "interpolateRdYlGn",
-        "exponent": 0.5,
-        "max": null,
-        "min": 0,
-        "mode": "opacity"
-      },
-      "dataFormat": "tsbuckets",
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "gridPos": {
-        "h": 22,
-        "w": 24,
-        "x": 0,
-        "y": 0
-      },
-      "heatmap": {},
-      "hideZeroBuckets": true,
-      "highlightCards": true,
-      "id": 2,
-      "interval": "60s",
-      "legend": {
-        "show": true
-      },
-      "pluginVersion": "7.5.4",
-      "reverseYBuckets": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(\r\n    max_over_time(tfs_device_exec_details_configuredevice_histogram_duration_bucket{pod=~\"[[pod]]\", step_name=~\"[[step_name]]\"}[1m]) -\r\n    min_over_time(tfs_device_exec_details_configuredevice_histogram_duration_bucket{pod=~\"[[pod]]\", step_name=~\"[[step_name]]\"}[1m])\r\n) by (le)",
-          "format": "heatmap",
-          "instant": false,
-          "interval": "1m",
-          "intervalFactor": 1,
-          "legendFormat": "{{le}}",
-          "queryType": "randomWalk",
-          "refId": "A"
-        }
-      ],
-      "title": "Histogram",
-      "tooltip": {
-        "show": true,
-        "showHistogram": true
-      },
-      "type": "heatmap",
-      "xAxis": {
-        "show": true
-      },
-      "xBucketNumber": null,
-      "xBucketSize": null,
-      "yAxis": {
-        "decimals": null,
-        "format": "s",
-        "logBase": 1,
-        "max": null,
-        "min": null,
-        "show": true,
-        "splitFactor": null
-      },
-      "yBucketBound": "auto",
-      "yBucketNumber": null,
-      "yBucketSize": null
-    }
-  ],
-  "refresh": false,
-  "schemaVersion": 27,
-  "style": "dark",
-  "tags": [],
-  "templating": {
-    "list": [
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, pod)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Pod",
-        "multi": true,
-        "name": "pod",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, pod)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "get_device",
-            "set_device"
-          ],
-          "value": [
-            "get_device",
-            "set_device"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, step_name)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Step Name",
-        "multi": true,
-        "name": "step_name",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, step_name)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      }
-    ]
-  },
-  "time": {
-    "from": "2023-04-20T15:11:48.272Z",
-    "to": "2023-04-20T15:18:10.464Z"
-  },
-  "timepicker": {},
-  "timezone": "",
-  "title": "TFS / ConfigureDevice Details",
-  "uid": "GfzKHbPVk",
-  "version": 4
-}
\ No newline at end of file
diff --git a/src/common/method_wrappers/tests/grafana_prometheus_device_driver.json b/src/common/method_wrappers/tests/grafana_prometheus_device_driver.json
deleted file mode 100644
index 2926a409b3b77b16c4e7b5d86ecd7d56f6acdebc..0000000000000000000000000000000000000000
--- a/src/common/method_wrappers/tests/grafana_prometheus_device_driver.json
+++ /dev/null
@@ -1,431 +0,0 @@
-{
-  "annotations": {
-    "list": [
-      {
-        "builtIn": 1,
-        "datasource": "-- Grafana --",
-        "enable": true,
-        "hide": true,
-        "iconColor": "rgba(0, 211, 255, 1)",
-        "name": "Annotations & Alerts",
-        "type": "dashboard"
-      }
-    ]
-  },
-  "editable": true,
-  "gnetId": null,
-  "graphTooltip": 0,
-  "id": 26,
-  "iteration": 1671318718779,
-  "links": [],
-  "panels": [
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 0
-      },
-      "hiddenSeries": false,
-      "id": 4,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_device_driver_[[method]]_counter_requests_started_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
-          "interval": "",
-          "legendFormat": "started",
-          "queryType": "randomWalk",
-          "refId": "A"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_device_driver_[[method]]_counter_requests_completed_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "completed",
-          "refId": "B"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_device_driver_[[method]]_counter_requests_failed_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "failed",
-          "refId": "C"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Requests",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:864",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:865",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    },
-    {
-      "cards": {
-        "cardPadding": null,
-        "cardRound": null
-      },
-      "color": {
-        "cardColor": "#b4ff00",
-        "colorScale": "linear",
-        "colorScheme": "interpolateRdYlGn",
-        "exponent": 0.5,
-        "max": null,
-        "min": 0,
-        "mode": "opacity"
-      },
-      "dataFormat": "tsbuckets",
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "gridPos": {
-        "h": 8,
-        "w": 24,
-        "x": 0,
-        "y": 6
-      },
-      "heatmap": {},
-      "hideZeroBuckets": true,
-      "highlightCards": true,
-      "id": 2,
-      "interval": "60s",
-      "legend": {
-        "show": true
-      },
-      "pluginVersion": "7.5.4",
-      "reverseYBuckets": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(\r\n    max_over_time(tfs_device_driver_[[method]]_histogram_duration_bucket{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_device_driver_[[method]]_histogram_duration_bucket{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"}[1m])\r\n) by (le)",
-          "format": "heatmap",
-          "instant": false,
-          "interval": "60s",
-          "intervalFactor": 1,
-          "legendFormat": "{{le}}",
-          "queryType": "randomWalk",
-          "refId": "A"
-        }
-      ],
-      "timeFrom": null,
-      "title": "Histogram",
-      "tooltip": {
-        "show": true,
-        "showHistogram": true
-      },
-      "type": "heatmap",
-      "xAxis": {
-        "show": true
-      },
-      "xBucketNumber": null,
-      "xBucketSize": null,
-      "yAxis": {
-        "decimals": null,
-        "format": "s",
-        "logBase": 1,
-        "max": null,
-        "min": null,
-        "show": true,
-        "splitFactor": null
-      },
-      "yBucketBound": "auto",
-      "yBucketNumber": null,
-      "yBucketSize": null
-    },
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 14
-      },
-      "hiddenSeries": false,
-      "id": 5,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_device_driver_[[method]]_histogram_duration_sum{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "total time",
-          "refId": "B"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Total Exec Time",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:407",
-          "format": "s",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:408",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    }
-  ],
-  "refresh": "5s",
-  "schemaVersion": 27,
-  "style": "dark",
-  "tags": [],
-  "templating": {
-    "list": [
-      {
-        "allValue": "",
-        "current": {
-          "selected": false,
-          "text": "setconfig",
-          "value": "setconfig"
-        },
-        "datasource": "prometheus",
-        "definition": "metrics(tfs_device_driver_.+)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": false,
-        "label": "Method",
-        "multi": false,
-        "name": "method",
-        "options": [],
-        "query": {
-          "query": "metrics(tfs_device_driver_.+)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/tfs_device_driver_(.+config)_histogram_duration_bucket/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, driver)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Driver",
-        "multi": true,
-        "name": "driver",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, driver)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, pod)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Pod",
-        "multi": true,
-        "name": "pod",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, pod)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/deviceservice-(.*)/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      }
-    ]
-  },
-  "time": {
-    "from": "now-15m",
-    "to": "now"
-  },
-  "timepicker": {},
-  "timezone": "",
-  "title": "TFS / Device / Driver",
-  "uid": "eAg-wsOVk",
-  "version": 30
-}
\ No newline at end of file
diff --git a/src/common/method_wrappers/tests/grafana_prometheus_service_handler.json b/src/common/method_wrappers/tests/grafana_prometheus_service_handler.json
deleted file mode 100644
index 48e770afe4bba9c2eb5df76d3532bf35d6cfe192..0000000000000000000000000000000000000000
--- a/src/common/method_wrappers/tests/grafana_prometheus_service_handler.json
+++ /dev/null
@@ -1,432 +0,0 @@
-{
-  "annotations": {
-    "list": [
-      {
-        "builtIn": 1,
-        "datasource": "-- Grafana --",
-        "enable": true,
-        "hide": true,
-        "iconColor": "rgba(0, 211, 255, 1)",
-        "name": "Annotations & Alerts",
-        "type": "dashboard"
-      }
-    ]
-  },
-  "editable": true,
-  "gnetId": null,
-  "graphTooltip": 0,
-  "id": 27,
-  "iteration": 1671319012315,
-  "links": [],
-  "panels": [
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 0
-      },
-      "hiddenSeries": false,
-      "id": 4,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_service_handler_[[method]]_counter_requests_started_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
-          "instant": false,
-          "interval": "",
-          "legendFormat": "started",
-          "queryType": "randomWalk",
-          "refId": "A"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_service_handler_[[method]]_counter_requests_completed_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "completed",
-          "refId": "B"
-        },
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_service_handler_[[method]]_counter_requests_failed_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "failed",
-          "refId": "C"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Requests",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:935",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:936",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    },
-    {
-      "cards": {
-        "cardPadding": null,
-        "cardRound": null
-      },
-      "color": {
-        "cardColor": "#b4ff00",
-        "colorScale": "linear",
-        "colorScheme": "interpolateRdYlGn",
-        "exponent": 0.5,
-        "max": null,
-        "min": 0,
-        "mode": "opacity"
-      },
-      "dataFormat": "tsbuckets",
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "gridPos": {
-        "h": 8,
-        "w": 24,
-        "x": 0,
-        "y": 6
-      },
-      "heatmap": {},
-      "hideZeroBuckets": true,
-      "highlightCards": true,
-      "id": 2,
-      "interval": "60s",
-      "legend": {
-        "show": true
-      },
-      "pluginVersion": "7.5.4",
-      "reverseYBuckets": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(\r\n    max_over_time(tfs_service_handler_[[method]]_histogram_duration_bucket{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_service_handler_[[method]]_histogram_duration_bucket{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"}[1m])\r\n) by (le)",
-          "format": "heatmap",
-          "instant": false,
-          "interval": "1m",
-          "intervalFactor": 1,
-          "legendFormat": "{{le}}",
-          "queryType": "randomWalk",
-          "refId": "A"
-        }
-      ],
-      "timeFrom": null,
-      "title": "Histogram",
-      "tooltip": {
-        "show": true,
-        "showHistogram": true
-      },
-      "type": "heatmap",
-      "xAxis": {
-        "show": true
-      },
-      "xBucketNumber": null,
-      "xBucketSize": null,
-      "yAxis": {
-        "decimals": null,
-        "format": "s",
-        "logBase": 1,
-        "max": null,
-        "min": null,
-        "show": true,
-        "splitFactor": null
-      },
-      "yBucketBound": "auto",
-      "yBucketNumber": null,
-      "yBucketSize": null
-    },
-    {
-      "aliasColors": {},
-      "bars": false,
-      "dashLength": 10,
-      "dashes": false,
-      "datasource": "prometheus",
-      "fieldConfig": {
-        "defaults": {},
-        "overrides": []
-      },
-      "fill": 1,
-      "fillGradient": 0,
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 14
-      },
-      "hiddenSeries": false,
-      "id": 5,
-      "legend": {
-        "alignAsTable": false,
-        "avg": false,
-        "current": false,
-        "max": false,
-        "min": false,
-        "rightSide": false,
-        "show": false,
-        "total": false,
-        "values": false
-      },
-      "lines": true,
-      "linewidth": 1,
-      "nullPointMode": "null",
-      "options": {
-        "alertThreshold": true
-      },
-      "percentage": false,
-      "pluginVersion": "7.5.4",
-      "pointradius": 2,
-      "points": false,
-      "renderer": "flot",
-      "seriesOverrides": [],
-      "spaceLength": 10,
-      "stack": false,
-      "steppedLine": false,
-      "targets": [
-        {
-          "exemplar": true,
-          "expr": "sum(tfs_service_handler_[[method]]_histogram_duration_sum{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
-          "hide": false,
-          "interval": "",
-          "legendFormat": "total time",
-          "refId": "B"
-        }
-      ],
-      "thresholds": [],
-      "timeFrom": null,
-      "timeRegions": [],
-      "timeShift": null,
-      "title": "Total Exec Time",
-      "tooltip": {
-        "shared": true,
-        "sort": 0,
-        "value_type": "individual"
-      },
-      "transformations": [],
-      "type": "graph",
-      "xaxis": {
-        "buckets": null,
-        "mode": "time",
-        "name": null,
-        "show": true,
-        "values": []
-      },
-      "yaxes": [
-        {
-          "$$hashKey": "object:407",
-          "format": "s",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": "0",
-          "show": true
-        },
-        {
-          "$$hashKey": "object:408",
-          "format": "short",
-          "label": null,
-          "logBase": 1,
-          "max": null,
-          "min": null,
-          "show": true
-        }
-      ],
-      "yaxis": {
-        "align": false,
-        "alignLevel": null
-      }
-    }
-  ],
-  "refresh": "5s",
-  "schemaVersion": 27,
-  "style": "dark",
-  "tags": [],
-  "templating": {
-    "list": [
-      {
-        "allValue": "",
-        "current": {
-          "selected": false,
-          "text": "setendpoint",
-          "value": "setendpoint"
-        },
-        "datasource": "prometheus",
-        "definition": "metrics(tfs_service_handler_.+)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": false,
-        "label": "Method",
-        "multi": false,
-        "name": "method",
-        "options": [],
-        "query": {
-          "query": "metrics(tfs_service_handler_.+)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/tfs_service_handler_(.+)_histogram_duration_bucket/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, handler)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Handler",
-        "multi": true,
-        "name": "handler",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, handler)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      },
-      {
-        "allValue": ".*",
-        "current": {
-          "selected": true,
-          "text": [
-            "All"
-          ],
-          "value": [
-            "$__all"
-          ]
-        },
-        "datasource": "prometheus",
-        "definition": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, pod)",
-        "description": null,
-        "error": null,
-        "hide": 0,
-        "includeAll": true,
-        "label": "Pod",
-        "multi": true,
-        "name": "pod",
-        "options": [],
-        "query": {
-          "query": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, pod)",
-          "refId": "StandardVariableQuery"
-        },
-        "refresh": 2,
-        "regex": "/serviceservice-(.*)/",
-        "skipUrlSync": false,
-        "sort": 0,
-        "tagValuesQuery": "",
-        "tags": [],
-        "tagsQuery": "",
-        "type": "query",
-        "useTags": false
-      }
-    ]
-  },
-  "time": {
-    "from": "now-15m",
-    "to": "now"
-  },
-  "timepicker": {},
-  "timezone": "",
-  "title": "TFS / Service / Handler",
-  "uid": "DNOhOIF4k",
-  "version": 16
-}
\ No newline at end of file
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index e7fec041802cc661b14617a8ebfec0864c738b39..38a6b735b32ee667c3be2f5381df84c40d773c06 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -37,8 +37,8 @@ LOGGER = logging.getLogger(__name__)
 
 METRICS_POOL = MetricsPool('Device', 'RPC')
 
-METRICS_POOL_DETAILS = MetricsPool('Device', 'exec_details', labels={
-    'step_name': '',
+METRICS_POOL_DETAILS = MetricsPool('Device', 'execution', labels={
+    'driver': '', 'operation': '', 'step': '',
 })
 
 class DeviceServiceServicerImpl(DeviceServiceServicer):
@@ -51,11 +51,15 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
 
     @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
     def AddDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId:
+        t0 = time.time()
+
         device_uuid = request.device_id.device_uuid.uuid
 
         connection_config_rules = check_connect_rules(request.device_config)
         check_no_endpoints(request.device_endpoints)
 
+        t1 = time.time()
+
         context_client = ContextClient()
         device = get_device(context_client, device_uuid, rw_copy=True)
         if device is None:
@@ -73,10 +77,15 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
         # update device_uuid to honor UUID provided by Context
         device_uuid = device.device_id.device_uuid.uuid
 
+        t2 = time.time()
+
         self.mutex_queues.wait_my_turn(device_uuid)
+        t3 = time.time()
         try:
             driver : _Driver = get_driver(self.driver_instance_cache, device)
 
+            t4 = time.time()
+
             errors = []
 
             # Sub-devices and sub-links are exposed by intermediate controllers or represent mgmt links.
@@ -86,13 +95,23 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
             new_sub_links : Dict[str, Link] = dict()
 
             if len(device.device_endpoints) == 0:
+                t5 = time.time()
                 # created from request, populate endpoints using driver
                 errors.extend(populate_endpoints(
                     device, driver, self.monitoring_loops, new_sub_devices, new_sub_links))
+                t6 = time.time()
+                t_pop_endpoints = t6 - t5
+            else:
+                t_pop_endpoints = None
 
             if len(device.device_config.config_rules) == len(connection_config_rules):
                 # created from request, populate config rules using driver
+                t7 = time.time()
                 errors.extend(populate_config_rules(device, driver))
+                t8 = time.time()
+                t_pop_config_rules = t8 - t7
+            else:
+                t_pop_config_rules = None
 
             # TODO: populate components
 
@@ -100,22 +119,60 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
                 for error in errors: LOGGER.error(error)
                 raise OperationFailedException('AddDevice', extra_details=errors)
 
+            t9 = time.time()
+
             device.device_operational_status = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
             device_id = context_client.SetDevice(device)
 
+            t10 = time.time()
+
             for sub_device in new_sub_devices.values():
                 context_client.SetDevice(sub_device)
 
+            t11 = time.time()
+
             for sub_links in new_sub_links.values():
                 context_client.SetLink(sub_links)
 
+            t12 = time.time()
+
             # Update endpoint monitoring resources with UUIDs
             device_with_uuids = get_device(
                 context_client, device_id.device_uuid.uuid, rw_copy=False, include_endpoints=True,
                 include_components=False, include_config_rules=False)
             populate_endpoint_monitoring_resources(device_with_uuids, self.monitoring_loops)
 
+            t13 = time.time()
+
             context_client.close()
+
+            t14 = time.time()
+
+            metrics_labels = dict(driver=driver.name, operation='add_device')
+
+            histogram_duration : Histogram = METRICS_POOL_DETAILS.get_or_create(
+                'details', MetricTypeEnum.HISTOGRAM_DURATION)
+            histogram_duration.labels(step='total'              , **metrics_labels).observe(t14-t0)
+            histogram_duration.labels(step='execution'          , **metrics_labels).observe(t14-t3)
+            histogram_duration.labels(step='endpoint_checks'    , **metrics_labels).observe(t1-t0)
+            histogram_duration.labels(step='get_device'         , **metrics_labels).observe(t2-t1)
+            histogram_duration.labels(step='wait_queue'         , **metrics_labels).observe(t3-t2)
+            histogram_duration.labels(step='get_driver'         , **metrics_labels).observe(t4-t3)
+            histogram_duration.labels(step='set_device'         , **metrics_labels).observe(t10-t9)
+            histogram_duration.labels(step='populate_monit_rsrc', **metrics_labels).observe(t13-t12)
+
+            if t_pop_endpoints is not None:
+                histogram_duration.labels(step='populate_endpoints', **metrics_labels).observe(t_pop_endpoints)
+
+            if t_pop_config_rules is not None:
+                histogram_duration.labels(step='populate_config_rules', **metrics_labels).observe(t_pop_config_rules)
+
+            if len(new_sub_devices) > 0:
+                histogram_duration.labels(step='set_sub_devices', **metrics_labels).observe(t11-t10)
+
+            if len(new_sub_links) > 0:
+                histogram_duration.labels(step='set_sub_links', **metrics_labels).observe(t12-t11)
+
             return device_id
         finally:
             self.mutex_queues.signal_done(device_uuid)
@@ -195,16 +252,18 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
 
             t9 = time.time()
 
+            metrics_labels = dict(driver=driver.name, operation='configure_device')
+
             histogram_duration : Histogram = METRICS_POOL_DETAILS.get_or_create(
-                'ConfigureDevice', MetricTypeEnum.HISTOGRAM_DURATION)
-            histogram_duration.labels(step_name='total'            ).observe(t9-t0)
-            histogram_duration.labels(step_name='wait_queue'       ).observe(t1-t0)
-            histogram_duration.labels(step_name='execution'        ).observe(t9-t1)
-            histogram_duration.labels(step_name='get_device'       ).observe(t3-t2)
-            histogram_duration.labels(step_name='split_rules'      ).observe(t5-t4)
-            histogram_duration.labels(step_name='configure_rules'  ).observe(t6-t5)
-            histogram_duration.labels(step_name='deconfigure_rules').observe(t7-t6)
-            histogram_duration.labels(step_name='set_device'       ).observe(t9-t8)
+                'details', MetricTypeEnum.HISTOGRAM_DURATION)
+            histogram_duration.labels(step='total'            , **metrics_labels).observe(t9-t0)
+            histogram_duration.labels(step='wait_queue'       , **metrics_labels).observe(t1-t0)
+            histogram_duration.labels(step='execution'        , **metrics_labels).observe(t9-t1)
+            histogram_duration.labels(step='get_device'       , **metrics_labels).observe(t3-t2)
+            histogram_duration.labels(step='split_rules'      , **metrics_labels).observe(t5-t4)
+            histogram_duration.labels(step='configure_rules'  , **metrics_labels).observe(t6-t5)
+            histogram_duration.labels(step='deconfigure_rules', **metrics_labels).observe(t7-t6)
+            histogram_duration.labels(step='set_device'       , **metrics_labels).observe(t9-t8)
 
             return device_id
         finally:
diff --git a/src/device/service/driver_api/_Driver.py b/src/device/service/driver_api/_Driver.py
index 947bc8570a941f8f666c87647d89c315b1bd202a..7adaec79dc99f9b7c836acaec886b0d5bda97fb8 100644
--- a/src/device/service/driver_api/_Driver.py
+++ b/src/device/service/driver_api/_Driver.py
@@ -27,7 +27,7 @@ RESOURCE_ACL = '__acl__'
 
 
 class _Driver:
-    def __init__(self, address: str, port: int, **settings) -> None:
+    def __init__(self, name : str, address: str, port: int, **settings) -> None:
         """ Initialize Driver.
             Parameters:
                 address : str
@@ -37,7 +37,22 @@ class _Driver:
                 **settings
                     Extra settings required by the driver.
         """
-        raise NotImplementedError()
+        self._name = name
+        self._address = address
+        self._port = port
+        self._settings = settings
+
+    @property
+    def name(self): return self._name
+
+    @property
+    def address(self): return self._address
+
+    @property
+    def port(self): return self._port
+
+    @property
+    def settings(self): return self._settings
 
     def Connect(self) -> bool:
         """ Connect to the Device.
diff --git a/src/device/service/drivers/emulated/EmulatedDriver.py b/src/device/service/drivers/emulated/EmulatedDriver.py
index 2acb288784d6da5b202f14c2534ee1a59486a20e..8f9453574a7333e599ea56158204627fcfdd3680 100644
--- a/src/device/service/drivers/emulated/EmulatedDriver.py
+++ b/src/device/service/drivers/emulated/EmulatedDriver.py
@@ -31,16 +31,18 @@ LOGGER = logging.getLogger(__name__)
 
 RE_GET_ENDPOINT_FROM_INTERFACE = re.compile(r'^\/interface\[([^\]]+)\].*')
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'emulated'})
+DRIVER_NAME = 'emulated'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class EmulatedDriver(_Driver):
-    def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called
+    def __init__(self, address : str, port : int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
         self.__lock = threading.Lock()
         self.__initial = TreeNode('.')
         self.__running = TreeNode('.')
         self.__subscriptions = TreeNode('.')
 
-        endpoints = settings.get('endpoints', [])
+        endpoints = self.settings.get('endpoints', [])
         endpoint_resources = []
         for endpoint in endpoints:
             endpoint_resource = compose_resource_endpoint(endpoint)
diff --git a/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py b/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py
index 96dfd2c15f6b359e254a6d6a24dfe42a546833ce..9498dc84cc6991fd2295371842fa8508c961f1bc 100644
--- a/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py
+++ b/src/device/service/drivers/ietf_l2vpn/IetfL2VpnDriver.py
@@ -39,21 +39,23 @@ ALL_RESOURCE_KEYS = [
 
 SERVICE_TYPE = 'ELINE'
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'ietf_l2vpn'})
+DRIVER_NAME = 'ietf_l2vpn'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class IetfL2VpnDriver(_Driver):
-    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
+    def __init__(self, address: str, port: int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
         self.__lock = threading.Lock()
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        username = settings.get('username')
-        password = settings.get('password')
-        scheme = settings.get('scheme', 'http')
-        wim = {'wim_url': '{:s}://{:s}:{:d}'.format(scheme, address, int(port))}
+        username = self.settings.get('username')
+        password = self.settings.get('password')
+        scheme = self.settings.get('scheme', 'http')
+        wim = {'wim_url': '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port))}
         wim_account = {'user': username, 'password': password}
         # Mapping updated dynamically with each request
         config = {'mapping_not_needed': False, 'service_endpoint_mapping': []}
-        self.dac = TfsDebugApiClient(address, int(port), scheme=scheme, username=username, password=password)
+        self.dac = TfsDebugApiClient(self.address, int(self.port), scheme=scheme, username=username, password=password)
         self.wim = WimconnectorIETFL2VPN(wim, wim_account, config=config)
         self.conn_info = {} # internal database emulating OSM storage provided to WIM Connectors
 
diff --git a/src/device/service/drivers/microwave/IETFApiDriver.py b/src/device/service/drivers/microwave/IETFApiDriver.py
index fad7cd0736ec35c5675461af241b2e7de2295dac..a8ef9094652378df8d1f1a55868849316b7ec95b 100644
--- a/src/device/service/drivers/microwave/IETFApiDriver.py
+++ b/src/device/service/drivers/microwave/IETFApiDriver.py
@@ -23,20 +23,22 @@ from .Tools import create_connectivity_service, find_key, config_getter, delete_
 
 LOGGER = logging.getLogger(__name__)
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'microwave'})
+DRIVER_NAME = 'microwave'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class IETFApiDriver(_Driver):
-    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
+    def __init__(self, address: str, port: int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
         self.__lock = threading.Lock()
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        username = settings.get('username')
-        password = settings.get('password')
+        username = self.settings.get('username')
+        password = self.settings.get('password')
         self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None
-        scheme = settings.get('scheme', 'http')
-        self.__ietf_root = '{:s}://{:s}:{:d}'.format(scheme, address, int(port))
-        self.__timeout = int(settings.get('timeout', 120))
-        self.__node_ids = set(settings.get('node_ids', []))
+        scheme = self.settings.get('scheme', 'http')
+        self.__ietf_root = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port))
+        self.__timeout = int(self.settings.get('timeout', 120))
+        self.__node_ids = set(self.settings.get('node_ids', []))
 
     def Connect(self) -> bool:
         url = self.__ietf_root + '/nmswebs/restconf/data/ietf-network:networks'
diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py
index 2399b9ac01258a21a4da6a9aa0e5bc09ea851951..ac67c4ab0d314adb3ce2af0aaffeda18e67334fc 100644
--- a/src/device/service/drivers/openconfig/OpenConfigDriver.py
+++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py
@@ -235,11 +235,13 @@ def edit_config(
             results = [e for _ in resources] # if commit fails, set exception in each resource
     return results
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'openconfig'})
+DRIVER_NAME = 'openconfig'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class OpenConfigDriver(_Driver):
-    def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called
-        self.__logger = logging.getLogger('{:s}:[{:s}:{:s}]'.format(str(__name__), str(address), str(port)))
+    def __init__(self, address : str, port : int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
+        self.__logger = logging.getLogger('{:s}:[{:s}:{:s}]'.format(str(__name__), str(self.address), str(self.port)))
         self.__lock = threading.Lock()
         #self.__initial = TreeNode('.')
         #self.__running = TreeNode('.')
@@ -249,11 +251,11 @@ class OpenConfigDriver(_Driver):
         self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events
         self.__scheduler.configure(
             jobstores = {'default': MemoryJobStore()},
-            executors = {'default': ThreadPoolExecutor(max_workers=1)},
+            executors = {'default': ThreadPoolExecutor(max_workers=1)}, # important! 1 = avoid concurrent requests
             job_defaults = {'coalesce': False, 'max_instances': 3},
             timezone=pytz.utc)
         self.__out_samples = queue.Queue()
-        self.__netconf_handler : NetconfSessionHandler = NetconfSessionHandler(address, port, **settings)
+        self.__netconf_handler = NetconfSessionHandler(self.address, self.port, **(self.settings))
         self.__samples_cache = SamplesCache(self.__netconf_handler, self.__logger)
 
     def Connect(self) -> bool:
diff --git a/src/device/service/drivers/p4/p4_driver.py b/src/device/service/drivers/p4/p4_driver.py
index de47f49c05b0f344999382883233a12eceb43c1b..49e6ed246b79c73d736d9fb91a6d4778cb08c90d 100644
--- a/src/device/service/drivers/p4/p4_driver.py
+++ b/src/device/service/drivers/p4/p4_driver.py
@@ -41,7 +41,8 @@ except ImportError:
 
 LOGGER = logging.getLogger(__name__)
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'p4'})
+DRIVER_NAME = 'p4'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class P4Driver(_Driver):
     """
diff --git a/src/device/service/drivers/transport_api/TransportApiDriver.py b/src/device/service/drivers/transport_api/TransportApiDriver.py
index 1991a34d0d797c48b6c2296435c0ebd0f3a8125a..98ed8e6aae613ea45519143c89e72af32f3b2620 100644
--- a/src/device/service/drivers/transport_api/TransportApiDriver.py
+++ b/src/device/service/drivers/transport_api/TransportApiDriver.py
@@ -23,19 +23,21 @@ from .Tools import create_connectivity_service, find_key, config_getter, delete_
 
 LOGGER = logging.getLogger(__name__)
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'transport_api'})
+DRIVER_NAME = 'transport_api'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class TransportApiDriver(_Driver):
-    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
+    def __init__(self, address: str, port: int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
         self.__lock = threading.Lock()
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        username = settings.get('username')
-        password = settings.get('password')
+        username = self.settings.get('username')
+        password = self.settings.get('password')
         self.__auth = HTTPBasicAuth(username, password) if username is not None and password is not None else None
-        scheme = settings.get('scheme', 'http')
-        self.__tapi_root = '{:s}://{:s}:{:d}'.format(scheme, address, int(port))
-        self.__timeout = int(settings.get('timeout', 120))
+        scheme = self.settings.get('scheme', 'http')
+        self.__tapi_root = '{:s}://{:s}:{:d}'.format(scheme, self.address, int(self.port))
+        self.__timeout = int(self.settings.get('timeout', 120))
 
     def Connect(self) -> bool:
         url = self.__tapi_root + '/restconf/data/tapi-common:context'
diff --git a/src/device/service/drivers/xr/XrDriver.py b/src/device/service/drivers/xr/XrDriver.py
index c1471a8136b0e5cd7791e019bb0bdafd2252f591..46269ff8904a0e20dbcb08202220412e64cb6283 100644
--- a/src/device/service/drivers/xr/XrDriver.py
+++ b/src/device/service/drivers/xr/XrDriver.py
@@ -33,21 +33,23 @@ urllib3.disable_warnings()
 
 LOGGER = logging.getLogger(__name__)
 
-METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': 'xr'})
+DRIVER_NAME = 'xr'
+METRICS_POOL = MetricsPool('Device', 'Driver', labels={'driver': DRIVER_NAME})
 
 class XrDriver(_Driver):
-    def __init__(self, address: str, port: int, **settings) -> None:    # pylint: disable=super-init-not-called
+    def __init__(self, address: str, port: int, **settings) -> None:
+        super().__init__(DRIVER_NAME, address, port, **settings)
         self.__lock = threading.Lock()
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        self.__timeout = int(settings.get('timeout', 120))
-        self.__cm_address = address
+        self.__timeout = int(self.settings.get('timeout', 120))
+        self.__cm_address = self.address
         # Mandatory key, an exception will get thrown if missing
-        self.__hub_module_name = settings["hub_module_name"]
+        self.__hub_module_name = self.settings["hub_module_name"]
 
         tls_verify = False # Currently using self signed certificates
-        username = settings.get("username", "xr-user-1")
-        password = settings.get("password", "xr-user-1")
+        username = self.settings.get("username", "xr-user-1")
+        password = self.settings.get("password", "xr-user-1")
 
         # Options are:
         #    disabled --> just import endpoints as usual
@@ -55,7 +57,7 @@ class XrDriver(_Driver):
         #                 (a remotely-controlled transport domain might exist between them)
         #    topology --> imports sub-devices and links connecting them.
         #                 (not supported by XR driver)
-        self.__import_topology = get_import_topology(settings, default=ImportTopologyEnum.DISABLED)
+        self.__import_topology = get_import_topology(self.settings, default=ImportTopologyEnum.DISABLED)
 
         # Options are:
         #    asynchronous --> operation considered complete when IPM responds with suitable status code,
@@ -64,12 +66,12 @@ class XrDriver(_Driver):
         #    lifecycle    --> operation is considered successfull once IPM has completed pluggaable configuration
         #                     or failed in it. This is typically unsuitable for production use
         #                     (as some optics may be transiently unreachable), but is convenient for demos and testin.
-        consistency_mode = ConsistencyMode.from_str(settings.get("consistency-mode", "asynchronous"))
+        consistency_mode = ConsistencyMode.from_str(self.settings.get("consistency-mode", "asynchronous"))
 
-        self.__cm_connection = CmConnection(address, int(port), username, password, self.__timeout, tls_verify = tls_verify, consistency_mode=consistency_mode)
+        self.__cm_connection = CmConnection(self.address, int(self.port), username, password, self.__timeout, tls_verify = tls_verify, consistency_mode=consistency_mode)
         self.__constellation = None
 
-        LOGGER.info(f"XrDriver instantiated, cm {address}:{port}, consistency mode {str(consistency_mode)}, {settings=}")
+        LOGGER.info(f"XrDriver instantiated, cm {self.address}:{self.port}, consistency mode {str(consistency_mode)}, {self.settings=}")
 
     def __str__(self):
         return f"{self.__hub_module_name}@{self.__cm_address}"
diff --git a/src/load_generator/command/__main__.py b/src/load_generator/command/__main__.py
index 7504eb6da6d6adea698249240abf2c4e4559297a..4fa2094e0fdc94b9665b2cfc86811e67809bcb5f 100644
--- a/src/load_generator/command/__main__.py
+++ b/src/load_generator/command/__main__.py
@@ -34,8 +34,14 @@ def main():
             RequestType.SLICE_L2NM,
             RequestType.SLICE_L3NM,
         ],
+        device_regex=r'.+',
+        endpoint_regex=r'.+',
         offered_load  = 50,
         holding_time  = 10,
+        availability_ranges   = [[0.0, 99.9999]],
+        capacity_gbps_ranges  = [[0.1, 100.00]],
+        e2e_latency_ms_ranges = [[5.0, 100.00]],
+        max_workers   = 10,
         dry_mode      = False,           # in dry mode, no request is sent to TeraFlowSDN
         record_to_dlt = False,           # if record_to_dlt, changes in device/link/service/slice are uploaded to DLT
         dlt_domain_id = 'dlt-perf-eval', # domain used to uploaded entities, ignored when record_to_dlt = False
diff --git a/src/load_generator/load_gen/Constants.py b/src/load_generator/load_gen/Constants.py
index 9ae3cdc1216891ca4dfcf01c1bd49d27bf4ef6f6..09cdecab124a776d3f71f66554db0934eaf1bb1c 100644
--- a/src/load_generator/load_gen/Constants.py
+++ b/src/load_generator/load_gen/Constants.py
@@ -27,4 +27,8 @@ ENDPOINT_COMPATIBILITY = {
     'PHOTONIC_MEDIA:DWDM:G_50GHZ:INPUT'  : 'PHOTONIC_MEDIA:DWDM:G_50GHZ:OUTPUT',
 }
 
-MAX_WORKER_THREADS = 10
\ No newline at end of file
+DEFAULT_AVAILABILITY_RANGES   = [[0.0, 99.9999]]
+DEFAULT_CAPACITY_GBPS_RANGES  = [[0.1, 100.00]]
+DEFAULT_E2E_LATENCY_MS_RANGES = [[5.0, 100.00]]
+
+DEFAULT_MAX_WORKERS = 10
diff --git a/src/load_generator/load_gen/Parameters.py b/src/load_generator/load_gen/Parameters.py
index f0de3ea1aa268c520fd214f7f621953289ac5bc9..5bb7a9b725f955a4186a21201e439f9cfaa71324 100644
--- a/src/load_generator/load_gen/Parameters.py
+++ b/src/load_generator/load_gen/Parameters.py
@@ -13,18 +13,41 @@
 # limitations under the License.
 
 from typing import List, Optional
+from load_generator.load_gen.Constants import (
+    DEFAULT_AVAILABILITY_RANGES, DEFAULT_CAPACITY_GBPS_RANGES, DEFAULT_E2E_LATENCY_MS_RANGES, DEFAULT_MAX_WORKERS)
+from load_generator.tools.ListScalarRange import Type_ListScalarRange
+
 
 class Parameters:
     def __init__(
-        self, num_requests : int, request_types : List[str], offered_load : Optional[float] = None,
-        inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, do_teardown : bool = True,
-        dry_mode : bool = False, record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None
+        self,
+        num_requests : int,
+        request_types : List[str],
+        device_regex : Optional[str] = None,
+        endpoint_regex : Optional[str] = None,
+        offered_load : Optional[float] = None,
+        inter_arrival_time : Optional[float] = None,
+        holding_time : Optional[float] = None,
+        availability_ranges : Type_ListScalarRange = DEFAULT_AVAILABILITY_RANGES,
+        capacity_gbps_ranges : Type_ListScalarRange = DEFAULT_CAPACITY_GBPS_RANGES,
+        e2e_latency_ms_ranges : Type_ListScalarRange = DEFAULT_E2E_LATENCY_MS_RANGES,
+        max_workers : int = DEFAULT_MAX_WORKERS,
+        do_teardown : bool = True,
+        dry_mode : bool = False,
+        record_to_dlt : bool = False,
+        dlt_domain_id : Optional[str] = None
     ) -> None:
         self._num_requests = num_requests
         self._request_types = request_types
+        self._device_regex = r'.*' if (device_regex is None or len(device_regex) == 0) else device_regex
+        self._endpoint_regex = r'.*' if (endpoint_regex is None or len(endpoint_regex) == 0) else endpoint_regex
         self._offered_load = offered_load
         self._inter_arrival_time = inter_arrival_time
         self._holding_time = holding_time
+        self._availability_ranges = availability_ranges
+        self._capacity_gbps_ranges = capacity_gbps_ranges
+        self._e2e_latency_ms_ranges = e2e_latency_ms_ranges
+        self._max_workers = max_workers
         self._do_teardown = do_teardown
         self._dry_mode = dry_mode
         self._record_to_dlt = record_to_dlt
@@ -50,6 +73,12 @@ class Parameters:
     @property
     def request_types(self): return self._request_types
 
+    @property
+    def device_regex(self): return self._device_regex
+
+    @property
+    def endpoint_regex(self): return self._endpoint_regex
+
     @property
     def offered_load(self): return self._offered_load
 
@@ -59,6 +88,18 @@ class Parameters:
     @property
     def holding_time(self): return self._holding_time
 
+    @property
+    def availability_ranges(self): return self._availability_ranges
+
+    @property
+    def capacity_gbps_ranges(self): return self._capacity_gbps_ranges
+
+    @property
+    def e2e_latency_ms_ranges(self): return self._e2e_latency_ms_ranges
+
+    @property
+    def max_workers(self): return self._max_workers
+
     @property
     def do_teardown(self): return self._do_teardown
 
diff --git a/src/load_generator/load_gen/RequestGenerator.py b/src/load_generator/load_gen/RequestGenerator.py
index cf56e221db0fbbe3f080d01af45cd36fc4ef56a0..974ce6f130e9c81f273f418b0a1440d148fcfb74 100644
--- a/src/load_generator/load_gen/RequestGenerator.py
+++ b/src/load_generator/load_gen/RequestGenerator.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import logging, json, random, re, threading
+import logging, json, random, re, threading, uuid
 from typing import Dict, Optional, Set, Tuple
 from common.proto.context_pb2 import Empty, IsolationLevelEnum, TopologyId
 from common.tools.grpc.Tools import grpc_message_to_json
@@ -28,6 +28,7 @@ from common.tools.object_factory.Slice import json_slice
 from common.tools.object_factory.Topology import json_topology_id
 from context.client.ContextClient import ContextClient
 from dlt.connector.client.DltConnectorClient import DltConnectorClient
+from load_generator.tools.ListScalarRange import generate_value
 from .Constants import ENDPOINT_COMPATIBILITY, RequestType
 from .DltTools import record_device_to_dlt, record_link_to_dlt
 from .Parameters import Parameters
@@ -53,6 +54,7 @@ class RequestGenerator:
         self._parameters = parameters
         self._lock = threading.Lock()
         self._num_generated = 0
+        self._num_released = 0
         self._available_device_endpoints : Dict[str, Set[str]] = dict()
         self._used_device_endpoints : Dict[str, Dict[str, str]] = dict()
         self._endpoint_ids_to_types : Dict[Tuple[str, str], str] = dict()
@@ -64,6 +66,9 @@ class RequestGenerator:
     @property
     def num_generated(self): return self._num_generated
 
+    @property
+    def num_released(self): return self._num_released
+
     @property
     def infinite_loop(self): return self._parameters.num_requests == 0
 
@@ -78,13 +83,21 @@ class RequestGenerator:
             if self._parameters.record_to_dlt:
                 dlt_domain_id = TopologyId(**json_topology_id('dlt-perf-eval'))
 
+            re_device = re.compile(r'^{:s}$'.format(self._parameters.device_regex))
+            re_endpoint = re.compile(r'^{:s}$'.format(self._parameters.endpoint_regex))
+
             devices = context_client.ListDevices(Empty())
             for device in devices.devices:
+                if self._parameters.record_to_dlt:
+                    record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id)
+
+                if re_device.match(device.name) is None: continue
                 device_uuid = device.device_id.device_uuid.uuid
                 self._device_data[device_uuid] = grpc_message_to_json(device)
 
                 _endpoints = self._available_device_endpoints.setdefault(device_uuid, set())
                 for endpoint in device.device_endpoints:
+                    if re_endpoint.match(endpoint.name) is None: continue
                     endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid
                     endpoints = self._device_endpoint_data.setdefault(device_uuid, dict())
                     endpoints[endpoint_uuid] = grpc_message_to_json(endpoint)
@@ -93,12 +106,12 @@ class RequestGenerator:
                     _endpoints.add(endpoint_uuid)
                     self._endpoint_ids_to_types.setdefault((device_uuid, endpoint_uuid), endpoint_type)
                     self._endpoint_types_to_ids.setdefault(endpoint_type, set()).add((device_uuid, endpoint_uuid))
-                
-                if self._parameters.record_to_dlt:
-                    record_device_to_dlt(dlt_connector_client, dlt_domain_id, device.device_id)
 
             links = context_client.ListLinks(Empty())
             for link in links.links:
+                if self._parameters.record_to_dlt:
+                    record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id)
+
                 for endpoint_id in link.link_endpoint_ids:
                     device_uuid = endpoint_id.device_id.device_uuid.uuid
                     endpoint_uuid = endpoint_id.endpoint_uuid.uuid
@@ -114,9 +127,6 @@ class RequestGenerator:
                     endpoint_key = (device_uuid, endpoint_uuid)
                     if endpoint_key not in endpoints_for_type: continue
                     endpoints_for_type.discard(endpoint_key)
-            
-                    if self._parameters.record_to_dlt:
-                        record_link_to_dlt(dlt_connector_client, dlt_domain_id, link.link_id)
 
     def dump_state(self) -> None:
         with self._lock:
@@ -186,28 +196,23 @@ class RequestGenerator:
             self._used_device_endpoints.setdefault(device_uuid, dict()).pop(endpoint_uuid, None)
             self._available_device_endpoints.setdefault(device_uuid, set()).add(endpoint_uuid)
 
-    def compose_request(self) -> Tuple[bool, Optional[Dict]]: # completed, request
+    def compose_request(self) -> Tuple[bool, Optional[Dict], str]: # completed, request
         with self._lock:
             if not self.infinite_loop and (self._num_generated >= self._parameters.num_requests):
                 LOGGER.info('Generation Done!')
-                return True, None # completed
-            self._num_generated += 1
-            num_request = self._num_generated
+                return True, None, None # completed
 
-        #request_uuid = str(uuid.uuid4())
-        request_uuid = 'svc_{:d}'.format(num_request)
-        
-        # choose request type
+        request_uuid = str(uuid.uuid4())
         request_type = random.choice(self._parameters.request_types)
 
         if request_type in {
             RequestType.SERVICE_L2NM, RequestType.SERVICE_L3NM, RequestType.SERVICE_TAPI, RequestType.SERVICE_MW
         }:
-            return False, self._compose_service(num_request, request_uuid, request_type)
+            return False, self._compose_service(request_uuid, request_type), request_type
         elif request_type in {RequestType.SLICE_L2NM, RequestType.SLICE_L3NM}:
-            return False, self._compose_slice(num_request, request_uuid, request_type)
+            return False, self._compose_slice(request_uuid, request_type), request_type
 
-    def _compose_service(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]:
+    def _compose_service(self, request_uuid : str, request_type : str) -> Optional[Dict]:
         # choose source endpoint
         src_endpoint_types = set(ENDPOINT_COMPATIBILITY.keys()) if request_type in {RequestType.SERVICE_TAPI} else None
         src = self._use_device_endpoint(request_uuid, request_type, endpoint_types=src_endpoint_types)
@@ -236,6 +241,10 @@ class RequestGenerator:
             self._release_device_endpoint(src_device_uuid, src_endpoint_uuid)
             return None
 
+        with self._lock:
+            self._num_generated += 1
+            num_request = self._num_generated
+
         # compose endpoints
         dst_device_uuid,dst_endpoint_uuid = dst
         endpoint_ids = [
@@ -244,9 +253,9 @@ class RequestGenerator:
         ]
 
         if request_type == RequestType.SERVICE_L2NM:
-            availability   = round(random.uniform(0.0, 99.9999), ndigits=5)
-            capacity_gbps  = round(random.uniform(0.1, 100.00), ndigits=2)
-            e2e_latency_ms = round(random.uniform(5.0, 100.00), ndigits=2)
+            availability   = generate_value(self._parameters.availability_ranges,   ndigits=5)
+            capacity_gbps  = generate_value(self._parameters.capacity_gbps_ranges,  ndigits=2)
+            e2e_latency_ms = generate_value(self._parameters.e2e_latency_ms_ranges, ndigits=2)
 
             constraints = [
                 json_constraint_sla_availability(1, True, availability),
@@ -293,9 +302,9 @@ class RequestGenerator:
                 request_uuid, endpoint_ids=endpoint_ids, constraints=constraints, config_rules=config_rules)
 
         elif request_type == RequestType.SERVICE_L3NM:
-            availability   = round(random.uniform(0.0, 99.9999), ndigits=5)
-            capacity_gbps  = round(random.uniform(0.1, 100.00), ndigits=2)
-            e2e_latency_ms = round(random.uniform(5.0, 100.00), ndigits=2)
+            availability   = generate_value(self._parameters.availability_ranges,   ndigits=5)
+            capacity_gbps  = generate_value(self._parameters.capacity_gbps_ranges,  ndigits=2)
+            e2e_latency_ms = generate_value(self._parameters.e2e_latency_ms_ranges, ndigits=2)
 
             constraints = [
                 json_constraint_sla_availability(1, True, availability),
@@ -382,7 +391,7 @@ class RequestGenerator:
             return json_service_l2nm_planned(
                 request_uuid, endpoint_ids=endpoint_ids, constraints=[], config_rules=config_rules)
 
-    def _compose_slice(self, num_request : int, request_uuid : str, request_type : str) -> Optional[Dict]:
+    def _compose_slice(self, request_uuid : str, request_type : str) -> Optional[Dict]:
         # choose source endpoint
         src = self._use_device_endpoint(request_uuid, request_type)
         if src is None:
@@ -403,6 +412,10 @@ class RequestGenerator:
             self._release_device_endpoint(src_device_uuid, src_endpoint_uuid)
             return None
 
+        with self._lock:
+            self._num_generated += 1
+            num_request = self._num_generated
+
         # compose endpoints
         dst_device_uuid,dst_endpoint_uuid = dst
         endpoint_ids = [
@@ -410,9 +423,10 @@ class RequestGenerator:
             json_endpoint_id(json_device_id(dst_device_uuid), dst_endpoint_uuid),
         ]
 
-        availability   = round(random.uniform(0.0, 99.9999), ndigits=5)
-        capacity_gbps  = round(random.uniform(0.1, 100.00), ndigits=2)
-        e2e_latency_ms = round(random.uniform(5.0, 100.00), ndigits=2)
+        availability   = generate_value(self._parameters.availability_ranges,   ndigits=5)
+        capacity_gbps  = generate_value(self._parameters.capacity_gbps_ranges,  ndigits=2)
+        e2e_latency_ms = generate_value(self._parameters.e2e_latency_ms_ranges, ndigits=2)
+
         constraints = [
             json_constraint_sla_availability(1, True, availability),
             json_constraint_sla_capacity(capacity_gbps),
@@ -503,8 +517,15 @@ class RequestGenerator:
                 device_uuid = endpoint_id['device_id']['device_uuid']['uuid']
                 endpoint_uuid = endpoint_id['endpoint_uuid']['uuid']
                 self._release_device_endpoint(device_uuid, endpoint_uuid)
+
+            with self._lock:
+                self._num_released += 1
+
         elif 'slice_id' in json_request:
             for endpoint_id in json_request['slice_endpoint_ids']:
                 device_uuid = endpoint_id['device_id']['device_uuid']['uuid']
                 endpoint_uuid = endpoint_id['endpoint_uuid']['uuid']
                 self._release_device_endpoint(device_uuid, endpoint_uuid)
+
+            with self._lock:
+                self._num_released += 1
diff --git a/src/load_generator/load_gen/RequestScheduler.py b/src/load_generator/load_gen/RequestScheduler.py
index 773a37eac258f8b3c16c966464ced124d3c77c85..340a5411bacee7b0aeb495963cdf65fbb5d14389 100644
--- a/src/load_generator/load_gen/RequestScheduler.py
+++ b/src/load_generator/load_gen/RequestScheduler.py
@@ -18,10 +18,11 @@ from apscheduler.jobstores.memory import MemoryJobStore
 from apscheduler.schedulers.blocking import BlockingScheduler
 from datetime import datetime, timedelta
 from typing import Dict, Optional
+from common.method_wrappers.Decorator import MetricsPool
 from common.proto.context_pb2 import Service, ServiceId, Slice, SliceId
+from common.tools.grpc.Tools import grpc_message_to_json_string
 from service.client.ServiceClient import ServiceClient
 from slice.client.SliceClient import SliceClient
-from .Constants import MAX_WORKER_THREADS
 from .DltTools import explore_entities_to_record, record_entities
 from .Parameters import Parameters
 from .RequestGenerator import RequestGenerator
@@ -31,6 +32,10 @@ logging.getLogger('apscheduler.scheduler').setLevel(logging.WARNING)
 
 LOGGER = logging.getLogger(__name__)
 
+METRICS_POOL = MetricsPool('LoadGen', 'Requests', labels={
+    'request_type': ''
+})
+
 class RequestScheduler:
     def __init__(
         self, parameters : Parameters, generator : RequestGenerator, scheduler_class=BlockingScheduler
@@ -38,7 +43,7 @@ class RequestScheduler:
         self._scheduler = scheduler_class()
         self._scheduler.configure(
             jobstores = {'default': MemoryJobStore()},
-            executors = {'default': ThreadPoolExecutor(max_workers=MAX_WORKER_THREADS)},
+            executors = {'default': ThreadPoolExecutor(max_workers=parameters.max_workers)},
             job_defaults = {
                 'coalesce': False,
                 'max_instances': 100,
@@ -52,6 +57,9 @@ class RequestScheduler:
     @property
     def num_generated(self): return min(self._generator.num_generated, self._parameters.num_requests)
 
+    @property
+    def num_released(self): return min(self._generator.num_released, self._parameters.num_requests)
+
     @property
     def infinite_loop(self): return self._generator.infinite_loop
 
@@ -64,11 +72,12 @@ class RequestScheduler:
         self._scheduler.add_job(
             self._request_setup, trigger='date', run_date=run_date, timezone=pytz.utc)
 
-    def _schedule_request_teardown(self, request : Dict) -> None:
+    def _schedule_request_teardown(self, request : Dict, request_type : str) -> None:
         ht  = random.expovariate(1.0 / self._parameters.holding_time)
         run_date = datetime.utcnow() + timedelta(seconds=ht)
+        args = (request, request_type)
         self._scheduler.add_job(
-            self._request_teardown, args=(request,), trigger='date', run_date=run_date, timezone=pytz.utc)
+            self._request_teardown, args=args, trigger='date', run_date=run_date, timezone=pytz.utc)
 
     def start(self):
         self._running.set()
@@ -80,7 +89,7 @@ class RequestScheduler:
         self._running.clear()
 
     def _request_setup(self) -> None:
-        completed,request = self._generator.compose_request()
+        completed, request, request_type = self._generator.compose_request()
         if completed:
             LOGGER.info('Generation Done!')
             #self._scheduler.shutdown()
@@ -91,6 +100,9 @@ class RequestScheduler:
 
         if request is None:
             LOGGER.warning('No resources available to compose new request')
+            metrics = METRICS_POOL.get_metrics_loadgen('setup', labels={'request_type': request_type})
+            _, _, _, _, counter_blocked = metrics
+            counter_blocked.inc()
             return
 
         if 'service_id' in request:
@@ -101,7 +113,7 @@ class RequestScheduler:
             dst_endpoint_uuid = request['service_endpoint_ids'][1]['endpoint_uuid']['uuid']
             LOGGER.info('Setup Service: uuid=%s src=%s:%s dst=%s:%s',
                 service_uuid, src_device_uuid, src_endpoint_uuid, dst_device_uuid, dst_endpoint_uuid)
-            self._create_update(service=request)
+            self._create_update(request_type, service=request)
 
         elif 'slice_id' in request:
             slice_uuid = request['slice_id']['slice_uuid']['uuid']
@@ -111,12 +123,12 @@ class RequestScheduler:
             dst_endpoint_uuid = request['slice_endpoint_ids'][1]['endpoint_uuid']['uuid']
             LOGGER.info('Setup Slice: uuid=%s src=%s:%s dst=%s:%s',
                 slice_uuid, src_device_uuid, src_endpoint_uuid, dst_device_uuid, dst_endpoint_uuid)
-            self._create_update(slice_=request)
+            self._create_update(request_type, slice_=request)
 
         if self._parameters.do_teardown:
-            self._schedule_request_teardown(request)
+            self._schedule_request_teardown(request, request_type)
 
-    def _request_teardown(self, request : Dict) -> None:
+    def _request_teardown(self, request : Dict, request_type : str) -> None:
         if 'service_id' in request:
             service_uuid = request['service_id']['service_uuid']['uuid']
             src_device_uuid = request['service_endpoint_ids'][0]['device_id']['device_uuid']['uuid']
@@ -125,7 +137,7 @@ class RequestScheduler:
             dst_endpoint_uuid = request['service_endpoint_ids'][1]['endpoint_uuid']['uuid']
             LOGGER.info('Teardown Service: uuid=%s src=%s:%s dst=%s:%s',
                 service_uuid, src_device_uuid, src_endpoint_uuid, dst_device_uuid, dst_endpoint_uuid)
-            self._delete(service_id=ServiceId(**(request['service_id'])))
+            self._delete(request_type, service_id=ServiceId(**(request['service_id'])))
 
         elif 'slice_id' in request:
             slice_uuid = request['slice_id']['slice_uuid']['uuid']
@@ -135,33 +147,64 @@ class RequestScheduler:
             dst_endpoint_uuid = request['slice_endpoint_ids'][1]['endpoint_uuid']['uuid']
             LOGGER.info('Teardown Slice: uuid=%s src=%s:%s dst=%s:%s',
                 slice_uuid, src_device_uuid, src_endpoint_uuid, dst_device_uuid, dst_endpoint_uuid)
-            self._delete(slice_id=SliceId(**(request['slice_id'])))
+            self._delete(request_type, slice_id=SliceId(**(request['slice_id'])))
 
         self._generator.release_request(request)
 
-    def _create_update(self, service : Optional[Dict] = None, slice_ : Optional[Dict] = None) -> None:
+    def _create_update(
+        self, request_type : str, service : Optional[Dict] = None, slice_ : Optional[Dict] = None
+    ) -> None:
         if self._parameters.dry_mode: return
 
+        metrics = METRICS_POOL.get_metrics_loadgen('setup', labels={'request_type': request_type})
+        histogram_duration, counter_started, counter_completed, counter_failed, _ = metrics
+
         service_id = None
         if service is not None:
+            service_client = ServiceClient()
+
             service_add = copy.deepcopy(service)
             service_add['service_endpoint_ids'] = []
             service_add['service_constraints'] = []
             service_add['service_config'] = {'config_rules': []}
+            service_add = Service(**service_add)
+            service = Service(**service)
+
+            with histogram_duration.time():
+                try:
+                    counter_started.inc()
+                    service_id = service_client.CreateService(service_add)
+                    service_id = service_client.UpdateService(service)
+                    counter_completed.inc()
+                except: # pylint: disable=bare-except
+                    counter_failed.inc()
+                    MSG = 'Exception Setting Up Service {:s}'
+                    LOGGER.exception(MSG.format(grpc_message_to_json_string(service)))
 
-            service_client = ServiceClient()
-            service_id = service_client.CreateService(Service(**service_add))
             service_client.close()
 
         slice_id = None
         if slice_ is not None:
+            slice_client = SliceClient()
+
             slice_add = copy.deepcopy(slice_)
             slice_add['slice_endpoint_ids'] = []
             slice_add['slice_constraints'] = []
             slice_add['slice_config'] = {'config_rules': []}
+            slice_add = Slice(**slice_add)
+            slice_ = Slice(**slice_)
+
+            with histogram_duration.time():
+                try:
+                    counter_started.inc()
+                    slice_id = slice_client.CreateSlice(slice_add)
+                    slice_id = slice_client.UpdateSlice(slice_)
+                    counter_completed.inc()
+                except: # pylint: disable=bare-except
+                    counter_failed.inc()
+                    MSG = 'Exception Setting Up Slice {:s}'
+                    LOGGER.exception(MSG.format(grpc_message_to_json_string(slice_)))
 
-            slice_client = SliceClient()
-            slice_id = slice_client.CreateSlice(Slice(**slice_add))
             slice_client.close()
 
         if self._parameters.record_to_dlt:
@@ -171,41 +214,47 @@ class RequestScheduler:
                 slices_to_record=slices_to_record, services_to_record=services_to_record,
                 devices_to_record=devices_to_record, delete=False)
 
-        service_id = None
-        if service is not None:
-            service_client = ServiceClient()
-            service_id = service_client.UpdateService(Service(**service))
-            service_client.close()
+    def _delete(
+        self, request_type : str, service_id : Optional[ServiceId] = None, slice_id : Optional[SliceId] = None
+    ) -> None:
+        if self._parameters.dry_mode: return
 
-        slice_id = None
-        if slice_ is not None:
-            slice_client = SliceClient()
-            slice_id = slice_client.UpdateSlice(Slice(**slice_))
-            slice_client.close()
+        metrics = METRICS_POOL.get_metrics_loadgen('teardown', labels={'request_type': request_type})
+        histogram_duration, counter_started, counter_completed, counter_failed, _ = metrics
 
         if self._parameters.record_to_dlt:
             entities_to_record = explore_entities_to_record(slice_id=slice_id, service_id=service_id)
             slices_to_record, services_to_record, devices_to_record = entities_to_record
-            record_entities(
-                slices_to_record=slices_to_record, services_to_record=services_to_record,
-                devices_to_record=devices_to_record, delete=False)
 
-    def _delete(self, service_id : Optional[ServiceId] = None, slice_id : Optional[SliceId] = None) -> None:
-        if self._parameters.dry_mode: return
+        if service_id is not None:
+            service_client = ServiceClient()
 
-        if self._parameters.record_to_dlt:
-            entities_to_record = explore_entities_to_record(slice_id=slice_id, service_id=service_id)
-            slices_to_record, services_to_record, devices_to_record = entities_to_record
+            with histogram_duration.time():
+                try:
+                    counter_started.inc()
+                    service_client.DeleteService(service_id)
+                    counter_completed.inc()
+                except: # pylint: disable=bare-except
+                    counter_failed.inc()
+                    MSG = 'Exception Tearing Down Service {:s}'
+                    LOGGER.exception(MSG.format(grpc_message_to_json_string(service_id)))
+
+            service_client.close()
 
         if slice_id is not None:
             slice_client = SliceClient()
-            slice_client.DeleteSlice(slice_id)
-            slice_client.close()
 
-        if service_id is not None:
-            service_client = ServiceClient()
-            service_client.DeleteService(service_id)
-            service_client.close()
+            with histogram_duration.time():
+                try:
+                    counter_started.inc()
+                    slice_client.DeleteSlice(slice_id)
+                    counter_completed.inc()
+                except: # pylint: disable=bare-except
+                    counter_failed.inc()
+                    MSG = 'Exception Tearing Down Slice {:s}'
+                    LOGGER.exception(MSG.format(grpc_message_to_json_string(slice_id)))
+
+            slice_client.close()
 
         if self._parameters.record_to_dlt:
             record_entities(
diff --git a/src/load_generator/service/LoadGeneratorServiceServicerImpl.py b/src/load_generator/service/LoadGeneratorServiceServicerImpl.py
index d66b0b2c10c5228e0c3d15759fc46b2c0770154d..866f9f089662598b08c8dd03d04b01fd63108f5a 100644
--- a/src/load_generator/service/LoadGeneratorServiceServicerImpl.py
+++ b/src/load_generator/service/LoadGeneratorServiceServicerImpl.py
@@ -21,6 +21,7 @@ from common.proto.load_generator_pb2_grpc import LoadGeneratorServiceServicer
 from load_generator.load_gen.Parameters import Parameters as LoadGen_Parameters
 from load_generator.load_gen.RequestGenerator import RequestGenerator
 from load_generator.load_gen.RequestScheduler import RequestScheduler
+from load_generator.tools.ListScalarRange import list_scalar_range__grpc_to_list, list_scalar_range__list_to_grpc
 from .Constants import REQUEST_TYPE_MAP, REQUEST_TYPE_REVERSE_MAP
 
 LOGGER = logging.getLogger(__name__)
@@ -34,15 +35,21 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer):
 
     def Start(self, request : Parameters, context : grpc.ServicerContext) -> Empty:
         self._parameters = LoadGen_Parameters(
-            num_requests       = request.num_requests,
-            request_types      = [REQUEST_TYPE_MAP[rt] for rt in request.request_types],
-            offered_load       = request.offered_load if request.offered_load > 1.e-12 else None,
-            holding_time       = request.holding_time if request.holding_time > 1.e-12 else None,
-            inter_arrival_time = request.inter_arrival_time if request.inter_arrival_time > 1.e-12 else None,
-            do_teardown        = request.do_teardown,   # if set, schedule tear down of requests
-            dry_mode           = request.dry_mode,      # in dry mode, no request is sent to TeraFlowSDN
-            record_to_dlt      = request.record_to_dlt, # if set, upload changes to DLT
-            dlt_domain_id      = request.dlt_domain_id, # domain used to uploaded entities (when record_to_dlt = True)
+            num_requests          = request.num_requests,
+            request_types         = [REQUEST_TYPE_MAP[rt] for rt in request.request_types],
+            device_regex          = request.device_regex,
+            endpoint_regex        = request.endpoint_regex,
+            offered_load          = request.offered_load if request.offered_load > 1.e-12 else None,
+            holding_time          = request.holding_time if request.holding_time > 1.e-12 else None,
+            inter_arrival_time    = request.inter_arrival_time if request.inter_arrival_time > 1.e-12 else None,
+            availability_ranges   = list_scalar_range__grpc_to_list(request.availability  ),
+            capacity_gbps_ranges  = list_scalar_range__grpc_to_list(request.capacity_gbps ),
+            e2e_latency_ms_ranges = list_scalar_range__grpc_to_list(request.e2e_latency_ms),
+            max_workers           = request.max_workers,
+            do_teardown           = request.do_teardown,   # if set, schedule tear down of requests
+            dry_mode              = request.dry_mode,      # in dry mode, no request is sent to TeraFlowSDN
+            record_to_dlt         = request.record_to_dlt, # if set, upload changes to DLT
+            dlt_domain_id         = request.dlt_domain_id, # domain used to uploaded entities (when record_to_dlt = True)
         )
 
         LOGGER.info('Initializing Generator...')
@@ -68,17 +75,28 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer):
 
         status = Status()
         status.num_generated = self._scheduler.num_generated
+        status.num_released  = self._scheduler.num_released
         status.infinite_loop = self._scheduler.infinite_loop
         status.running       = self._scheduler.running
-        status.parameters.num_requests       = params.num_requests          # pylint: disable=no-member
-        status.parameters.offered_load       = params.offered_load          # pylint: disable=no-member
-        status.parameters.holding_time       = params.holding_time          # pylint: disable=no-member
-        status.parameters.inter_arrival_time = params.inter_arrival_time    # pylint: disable=no-member
-        status.parameters.do_teardown        = params.do_teardown           # pylint: disable=no-member
-        status.parameters.dry_mode           = params.dry_mode              # pylint: disable=no-member
-        status.parameters.record_to_dlt      = params.record_to_dlt         # pylint: disable=no-member
-        status.parameters.dlt_domain_id      = params.dlt_domain_id         # pylint: disable=no-member
-        status.parameters.request_types.extend(request_types)               # pylint: disable=no-member
+
+        stat_pars = status.parameters                               # pylint: disable=no-member
+        stat_pars.num_requests       = params.num_requests          # pylint: disable=no-member
+        stat_pars.device_regex       = params.device_regex          # pylint: disable=no-member
+        stat_pars.endpoint_regex     = params.endpoint_regex        # pylint: disable=no-member
+        stat_pars.offered_load       = params.offered_load          # pylint: disable=no-member
+        stat_pars.holding_time       = params.holding_time          # pylint: disable=no-member
+        stat_pars.inter_arrival_time = params.inter_arrival_time    # pylint: disable=no-member
+        stat_pars.max_workers        = params.max_workers           # pylint: disable=no-member
+        stat_pars.do_teardown        = params.do_teardown           # pylint: disable=no-member
+        stat_pars.dry_mode           = params.dry_mode              # pylint: disable=no-member
+        stat_pars.record_to_dlt      = params.record_to_dlt         # pylint: disable=no-member
+        stat_pars.dlt_domain_id      = params.dlt_domain_id         # pylint: disable=no-member
+        stat_pars.request_types.extend(request_types)               # pylint: disable=no-member
+
+        list_scalar_range__list_to_grpc(params.availability_ranges,   stat_pars.availability  ) # pylint: disable=no-member
+        list_scalar_range__list_to_grpc(params.capacity_gbps_ranges,  stat_pars.capacity_gbps ) # pylint: disable=no-member
+        list_scalar_range__list_to_grpc(params.e2e_latency_ms_ranges, stat_pars.e2e_latency_ms) # pylint: disable=no-member
+
         return status
 
     def Stop(self, request : Empty, context : grpc.ServicerContext) -> Empty:
diff --git a/src/load_generator/service/__main__.py b/src/load_generator/service/__main__.py
index 227099c59aa57f420c842a6210f3b8b146b23cda..7051a9a18bb2a86e2ca298b9ddfdc32f3e3fa6e7 100644
--- a/src/load_generator/service/__main__.py
+++ b/src/load_generator/service/__main__.py
@@ -13,14 +13,15 @@
 # limitations under the License.
 
 import logging, signal, sys, threading
+from prometheus_client import start_http_server
 from common.Constants import ServiceNameEnum
 from common.Settings import (
-    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level,
+    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name, get_log_level, get_metrics_port,
     wait_for_environment_variables)
 from .LoadGeneratorService import LoadGeneratorService
 
-log_level = get_log_level()
-logging.basicConfig(level=log_level, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s")
+LOG_LEVEL = get_log_level()
+logging.basicConfig(level=LOG_LEVEL, format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s")
 LOGGER = logging.getLogger(__name__)
 
 terminate = threading.Event()
@@ -39,10 +40,13 @@ def main():
         get_env_var_name(ServiceNameEnum.SLICE,   ENVVAR_SUFIX_SERVICE_PORT_GRPC),
     ])
 
+    LOGGER.info('Starting...')
     signal.signal(signal.SIGINT,  signal_handler)
     signal.signal(signal.SIGTERM, signal_handler)
 
-    LOGGER.info('Starting...')
+    # Start metrics server
+    metrics_port = get_metrics_port()
+    start_http_server(metrics_port)
 
     # Starting load generator service
     grpc_service = LoadGeneratorService()
diff --git a/src/load_generator/tools/ListScalarRange.py b/src/load_generator/tools/ListScalarRange.py
new file mode 100644
index 0000000000000000000000000000000000000000..9a5a5f39940049adee6dfbe35befd815db9256fe
--- /dev/null
+++ b/src/load_generator/tools/ListScalarRange.py
@@ -0,0 +1,99 @@
+# 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.
+
+import random
+from typing import List, Optional, Tuple, Union
+
+from common.proto.load_generator_pb2 import ScalarOrRange
+
+# RegEx to validate strings formatted as: '1, 2.3, 4.5  .. 6.7 , .8...9, 10., .11'
+# IMPORTANT: this regex just validates data, it does not extract the pieces of data!
+RE_FLOAT = r'[\ ]*[0-9]*[\.]?[0-9]*[\ ]*'
+RE_RANGE = RE_FLOAT + r'(\.\.' + RE_FLOAT + r')?'
+RE_SCALAR_RANGE_LIST  = RE_RANGE + r'(\,' + RE_RANGE + r')*'
+
+Type_ListScalarRange = List[Union[float, Tuple[float, float]]]
+
+def parse_list_scalar_range(value : str) -> Type_ListScalarRange:
+    str_value = str(value).replace(' ', '')
+    ranges = [[float(value) for value in item.split('..')] for item in str_value.split(',')]
+    return ranges
+
+def list_scalar_range__list_to_grpc(list_scalar_range : Type_ListScalarRange, obj : List[ScalarOrRange]) -> None:
+    for i,scalar_or_range in enumerate(list_scalar_range):
+        if isinstance(scalar_or_range, (float, str)):
+            _scalar = obj.add()
+            _scalar.scalar = float(scalar_or_range)
+        elif isinstance(scalar_or_range, (list, tuple)):
+            if len(scalar_or_range) == 1:
+                _scalar = obj.add()
+                _scalar.scalar = float(scalar_or_range[0])
+            elif len(scalar_or_range) == 2:
+                _range = obj.add()
+                _range.range.minimum = float(scalar_or_range[0])
+                _range.range.maximum = float(scalar_or_range[1])
+            else:
+                MSG = 'List/tuple with {:d} items in item(#{:d}, {:s})'
+                raise NotImplementedError(MSG.format(len(scalar_or_range), i, str(scalar_or_range)))
+        else:
+            MSG = 'Type({:s}) in item(#{:d}, {:s})'
+            raise NotImplementedError(MSG.format(str(type(scalar_or_range), i, str(scalar_or_range))))
+
+def list_scalar_range__grpc_to_str(obj : List[ScalarOrRange]) -> str:
+    str_items = list()
+    for item in obj:
+        item_kind = item.WhichOneof('value')
+        if item_kind == 'scalar':
+            str_items.append(str(item.scalar))
+        elif item_kind == 'range':
+            str_items.append('{:s}..{:s}'.format(str(item.range.minimum), str(item.range.maximum)))
+        else:
+            raise NotImplementedError('Unsupported ScalarOrRange kind({:s})'.format(str(item_kind)))
+    return ','.join(str_items)
+
+def list_scalar_range__grpc_to_list(obj : List[ScalarOrRange]) -> Type_ListScalarRange:
+    list_scalar_range = list()
+    for item in obj:
+        item_kind = item.WhichOneof('value')
+        if item_kind == 'scalar':
+            scalar_or_range = float(item.scalar)
+        elif item_kind == 'range':
+            scalar_or_range = (float(item.range.minimum), float(item.range.maximum))
+        else:
+            raise NotImplementedError('Unsupported ScalarOrRange kind({:s})'.format(str(item_kind)))
+        list_scalar_range.append(scalar_or_range)
+    return list_scalar_range
+
+def generate_value(
+    list_scalar_range : Type_ListScalarRange, ndigits : Optional[int] = None
+) -> float:
+    scalar_or_range = random.choice(list_scalar_range)
+    if isinstance(scalar_or_range, (float, str)):
+        value = float(scalar_or_range)
+    elif isinstance(scalar_or_range, (list, tuple)):
+        if len(scalar_or_range) == 1:
+            value = float(scalar_or_range[0])
+        elif len(scalar_or_range) == 2:
+            minimum = float(scalar_or_range[0])
+            maximum = float(scalar_or_range[1])
+            value = random.uniform(minimum, maximum)
+        else:
+            MSG = 'List/tuple with {:d} items in item({:s})'
+            raise NotImplementedError(MSG.format(len(scalar_or_range), str(scalar_or_range)))
+    else:
+        MSG = 'Type({:s}) in item({:s})'
+        raise NotImplementedError(MSG.format(str(type(scalar_or_range), str(scalar_or_range))))
+
+    if ndigits is None: return value
+    return round(value, ndigits=ndigits)
diff --git a/src/load_generator/tools/__init__.py b/src/load_generator/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..38d04994fb0fa1951fb465bc127eb72659dc2eaf
--- /dev/null
+++ b/src/load_generator/tools/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/pathcomp/backend/pathComp_tools.h b/src/pathcomp/backend/pathComp_tools.h
index cac66f81c561502a6d93249f5e44a6195cb0f61b..84334eb5e1d47199e8a71bb09c3b541625d66af2 100644
--- a/src/pathcomp/backend/pathComp_tools.h
+++ b/src/pathcomp/backend/pathComp_tools.h
@@ -124,7 +124,7 @@ struct map_nodes_t {
     gint numMapNodes;
 };
 
-#define MAX_NUM_VERTICES				20 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used
+#define MAX_NUM_VERTICES				100 // 100 # LGR: reduced from 100 to 20 to divide by 5 the memory used
 #define MAX_NUM_EDGES					5 // 100 # LGR: reduced from 100 to 5 to divide by 20 the memory used
 // Structures for the graph composition
 struct targetNodes_t {
@@ -249,7 +249,7 @@ struct endPoint_t {
 // Structure for the device contents
 ///////////////////////////////////////////////////////////////////
 #define MAX_DEV_TYPE_SIZE				128
-#define MAX_DEV_ENDPOINT_LENGTH			50	// 10 # LGR: controllers might have large number of endpoints
+#define MAX_DEV_ENDPOINT_LENGTH			100	// 10 # LGR: controllers might have large number of endpoints
 struct device_t {
 	gdouble power_idle; // power idle (baseline) of the switch in Watts
 	gint operational_status; // 0 - Undefined, 1 - Disabled, 2 - Enabled
diff --git a/src/webui/Dockerfile b/src/webui/Dockerfile
index 7c718890fcf3f07b32f66eca2ecab41f2eb30fbb..2a1510954dbd2a9b0817f94145baaa22ac9d3a3f 100644
--- a/src/webui/Dockerfile
+++ b/src/webui/Dockerfile
@@ -79,6 +79,7 @@ COPY --chown=webui:webui src/device/__init__.py device/__init__.py
 COPY --chown=webui:webui src/device/client/. device/client/
 COPY --chown=webui:webui src/load_generator/__init__.py load_generator/__init__.py
 COPY --chown=webui:webui src/load_generator/client/. load_generator/client/
+COPY --chown=webui:webui src/load_generator/tools/. load_generator/tools/
 COPY --chown=webui:webui src/service/__init__.py service/__init__.py
 COPY --chown=webui:webui src/service/client/. service/client/
 COPY --chown=webui:webui src/slice/__init__.py slice/__init__.py
diff --git a/src/webui/grafana_prom_component_rpc.json b/src/webui/grafana_prom_component_rpc.json
new file mode 100644
index 0000000000000000000000000000000000000000..ce40c2854df2f71fe07601ca4fada945cab22fa6
--- /dev/null
+++ b/src/webui/grafana_prom_component_rpc.json
@@ -0,0 +1,427 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": "-- Grafana --",
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "gnetId": null,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1671297223428,
+    "links": [],
+    "panels": [
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "hiddenSeries": false,
+        "id": 4,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_started_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "started",
+            "refId": "A"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_completed_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "completed",
+            "refId": "B"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_[[component]]_rpc_[[method]]_counter_requests_failed_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "failed",
+            "refId": "C"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Requests",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:935",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:936",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      },
+      {
+        "cards": {
+          "cardPadding": null,
+          "cardRound": null
+        },
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "max": null,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "gridPos": {
+          "h": 8,
+          "w": 24,
+          "x": 0,
+          "y": 6
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "1m",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "refId": "A"
+          }
+        ],
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "xBucketNumber": null,
+        "xBucketSize": null,
+        "yAxis": {
+          "decimals": null,
+          "format": "s",
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true,
+          "splitFactor": null
+        },
+        "yBucketBound": "auto",
+        "yBucketNumber": null,
+        "yBucketSize": null
+      },
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 14
+        },
+        "hiddenSeries": false,
+        "id": 5,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_[[component]]_rpc_[[method]]_histogram_duration_sum{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "total time",
+            "refId": "B"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Total Exec Time",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:407",
+            "format": "s",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:408",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 27,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": null,
+          "current": {
+            "selected": false,
+            "text": "context",
+            "value": "context"
+          },
+          "datasource": "prometheus",
+          "definition": "metrics(tfs_)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": false,
+          "label": "Component",
+          "multi": false,
+          "name": "component",
+          "options": [],
+          "query": {
+            "query": "metrics(tfs_)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/tfs_(.+)_rpc_.*/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": "",
+          "current": {
+            "selected": false,
+            "text": "getcontext",
+            "value": "getcontext"
+          },
+          "datasource": "prometheus",
+          "definition": "metrics(tfs_[[component]]_rpc_)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": false,
+          "label": "Method",
+          "multi": false,
+          "name": "method",
+          "options": [],
+          "query": {
+            "query": "metrics(tfs_[[component]]_rpc_)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/tfs_[[component]]_rpc_(.+)_histogram_duration_bucket/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket, pod)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_[[component]]_rpc_[[method]]_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / Component RPCs",
+    "uid": "tfs-comp-rpc",
+    "version": 21
+  }
+}
diff --git a/src/webui/grafana_prom_device_driver.json b/src/webui/grafana_prom_device_driver.json
new file mode 100644
index 0000000000000000000000000000000000000000..af4ccca88a905b7ebb25ca0e23506b7b618011ad
--- /dev/null
+++ b/src/webui/grafana_prom_device_driver.json
@@ -0,0 +1,432 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": "-- Grafana --",
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "gnetId": null,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1671318718779,
+    "links": [],
+    "panels": [
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "hiddenSeries": false,
+        "id": 4,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_device_driver_[[method]]_counter_requests_started_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "started",
+            "refId": "A"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_device_driver_[[method]]_counter_requests_completed_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "completed",
+            "refId": "B"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_device_driver_[[method]]_counter_requests_failed_total{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "failed",
+            "refId": "C"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Requests",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:864",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:865",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      },
+      {
+        "cards": {
+          "cardPadding": null,
+          "cardRound": null
+        },
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "max": null,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "gridPos": {
+          "h": 8,
+          "w": 24,
+          "x": 0,
+          "y": 6
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_device_driver_[[method]]_histogram_duration_bucket{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_device_driver_[[method]]_histogram_duration_bucket{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "60s",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "refId": "A"
+          }
+        ],
+        "timeFrom": null,
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "xBucketNumber": null,
+        "xBucketSize": null,
+        "yAxis": {
+          "decimals": null,
+          "format": "s",
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true,
+          "splitFactor": null
+        },
+        "yBucketBound": "auto",
+        "yBucketNumber": null,
+        "yBucketSize": null
+      },
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 14
+        },
+        "hiddenSeries": false,
+        "id": 5,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_device_driver_[[method]]_histogram_duration_sum{driver=~\"[[driver]]\", pod=~\"deviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "total time",
+            "refId": "B"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Total Exec Time",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:407",
+            "format": "s",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:408",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 27,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": "",
+          "current": {
+            "selected": false,
+            "text": "setconfig",
+            "value": "setconfig"
+          },
+          "datasource": "prometheus",
+          "definition": "metrics(tfs_device_driver_.+)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": false,
+          "label": "Method",
+          "multi": false,
+          "name": "method",
+          "options": [],
+          "query": {
+            "query": "metrics(tfs_device_driver_.+)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/tfs_device_driver_(.+config)_histogram_duration_bucket/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, driver)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Driver",
+          "multi": true,
+          "name": "driver",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, driver)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, pod)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_driver_[[method]]_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/deviceservice-(.*)/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / Device / Driver",
+    "uid": "tfs-dev-drv",
+    "version": 30
+  }
+}
diff --git a/src/webui/grafana_prom_device_exec_details.json b/src/webui/grafana_prom_device_exec_details.json
new file mode 100644
index 0000000000000000000000000000000000000000..a18c2b91cabd942dd5908ff3e6b3966528e62fa0
--- /dev/null
+++ b/src/webui/grafana_prom_device_exec_details.json
@@ -0,0 +1,258 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "target": {
+            "limit": 100,
+            "matchAny": false,
+            "tags": [],
+            "type": "dashboard"
+          },
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "fiscalYearStartMonth": 0,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1683036452435,
+    "links": [],
+    "liveNow": false,
+    "panels": [
+      {
+        "cards": {},
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": {
+          "type": "prometheus",
+          "uid": "prometheus"
+        },
+        "gridPos": {
+          "h": 22,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "datasource": {
+              "type": "prometheus",
+              "uid": "prometheus"
+            },
+            "editorMode": "code",
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_device_execution_details_histogram_duration_bucket{driver=~\"[[driver]]\", operation=~\"[[operation]]\", step=~\"[[step]]\"}[1m]) -\r\n    min_over_time(tfs_device_execution_details_histogram_duration_bucket{driver=~\"[[driver]]\", operation=~\"[[operation]]\", step=~\"[[step]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "1m",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "range": true,
+            "refId": "A"
+          }
+        ],
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "yAxis": {
+          "format": "s",
+          "logBase": 1,
+          "show": true
+        },
+        "yBucketBound": "auto"
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 36,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "label_values(tfs_device_execution_details_histogram_duration_bucket, operation)",
+          "hide": 0,
+          "includeAll": true,
+          "label": "Operation",
+          "multi": true,
+          "name": "operation",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_execution_details_histogram_duration_bucket, operation)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "label_values(tfs_device_execution_details_histogram_duration_bucket, driver)",
+          "hide": 0,
+          "includeAll": true,
+          "label": "Driver",
+          "multi": true,
+          "name": "driver",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_execution_details_histogram_duration_bucket, driver)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "label_values(tfs_device_execution_details_histogram_duration_bucket, step)",
+          "hide": 0,
+          "includeAll": true,
+          "label": "Step",
+          "multi": true,
+          "name": "step",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_execution_details_histogram_duration_bucket, step)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "label_values(tfs_device_execution_details_histogram_duration_bucket, pod)",
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_execution_details_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / Device Execution Details",
+    "uid": "tfs-dev-exec",
+    "version": 4,
+    "weekStart": ""
+  }
+}
diff --git a/src/webui/grafana_prom_load_generator.json b/src/webui/grafana_prom_load_generator.json
new file mode 100644
index 0000000000000000000000000000000000000000..efdc8a1180e0d44f726becf5c8125c34779f7c78
--- /dev/null
+++ b/src/webui/grafana_prom_load_generator.json
@@ -0,0 +1,399 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": {
+            "type": "datasource",
+            "uid": "grafana"
+          },
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "target": {
+            "limit": 100,
+            "matchAny": false,
+            "tags": [],
+            "type": "dashboard"
+          },
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "fiscalYearStartMonth": 0,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1682528742676,
+    "links": [],
+    "liveNow": false,
+    "panels": [
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": {
+          "type": "prometheus",
+          "uid": "prometheus"
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "hiddenSeries": false,
+        "id": 4,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "8.5.22",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "datasource": {
+              "type": "prometheus",
+              "uid": "prometheus"
+            },
+            "exemplar": true,
+            "expr": "sum(tfs_loadgen_requests_[[method]]_counter_requests_started_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "started",
+            "refId": "A"
+          },
+          {
+            "datasource": {
+              "type": "prometheus",
+              "uid": "prometheus"
+            },
+            "exemplar": true,
+            "expr": "sum(tfs_loadgen_requests_[[method]]_counter_requests_completed_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "completed",
+            "refId": "B"
+          },
+          {
+            "datasource": {
+              "type": "prometheus",
+              "uid": "prometheus"
+            },
+            "exemplar": true,
+            "expr": "sum(tfs_loadgen_requests_[[method]]_counter_requests_failed_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "failed",
+            "refId": "C"
+          },
+          {
+            "datasource": {
+              "type": "prometheus",
+              "uid": "prometheus"
+            },
+            "editorMode": "code",
+            "exemplar": true,
+            "expr": "sum(tfs_loadgen_requests_[[method]]_counter_requests_blocked_total{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "blocked",
+            "range": true,
+            "refId": "D"
+          }
+        ],
+        "thresholds": [],
+        "timeRegions": [],
+        "title": "Requests",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "mode": "time",
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:935",
+            "format": "short",
+            "logBase": 1,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:936",
+            "format": "short",
+            "logBase": 1,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false
+        }
+      },
+      {
+        "cards": {},
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": {
+          "type": "prometheus",
+          "uid": "prometheus"
+        },
+        "gridPos": {
+          "h": 8,
+          "w": 24,
+          "x": 0,
+          "y": 6
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_loadgen_requests_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_loadgen_requests_[[method]]_histogram_duration_bucket{pod=~\"[[pod]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "1m",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "refId": "A"
+          }
+        ],
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "yAxis": {
+          "format": "s",
+          "logBase": 1,
+          "show": true
+        },
+        "yBucketBound": "auto"
+      },
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": {
+          "type": "prometheus",
+          "uid": "prometheus"
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 14
+        },
+        "hiddenSeries": false,
+        "id": 5,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "8.5.22",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_loadgen_requests_[[method]]_histogram_duration_sum{pod=~\"[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "total time",
+            "refId": "B"
+          }
+        ],
+        "thresholds": [],
+        "timeRegions": [],
+        "title": "Total Exec Time",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "mode": "time",
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:407",
+            "format": "s",
+            "logBase": 1,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:408",
+            "format": "short",
+            "logBase": 1,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false
+        }
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 36,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": false,
+            "text": "setup",
+            "value": "setup"
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "metrics(tfs_loadgen_requests_)",
+          "hide": 0,
+          "includeAll": false,
+          "label": "Method",
+          "multi": false,
+          "name": "method",
+          "options": [],
+          "query": {
+            "query": "metrics(tfs_loadgen_requests_)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/tfs_loadgen_requests_(.+)_histogram_duration_bucket/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": {
+            "type": "prometheus",
+            "uid": "prometheus"
+          },
+          "definition": "label_values(tfs_loadgen_requests_[[method]]_histogram_duration_bucket, pod)",
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_loadgen_requests_[[method]]_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / Load Generator Status",
+    "uid": "tfs-loadgen-stats",
+    "version": 3,
+    "weekStart": ""
+  }
+}
diff --git a/src/webui/grafana_prom_service_handler.json b/src/webui/grafana_prom_service_handler.json
new file mode 100644
index 0000000000000000000000000000000000000000..86f4b13d6f654af7d1f32f865ae2f6f508b7296c
--- /dev/null
+++ b/src/webui/grafana_prom_service_handler.json
@@ -0,0 +1,432 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": "-- Grafana --",
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "gnetId": null,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1671319012315,
+    "links": [],
+    "panels": [
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "hiddenSeries": false,
+        "id": 4,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_service_handler_[[method]]_counter_requests_started_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "started",
+            "refId": "A"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_service_handler_[[method]]_counter_requests_completed_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "completed",
+            "refId": "B"
+          },
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_service_handler_[[method]]_counter_requests_failed_total{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "failed",
+            "refId": "C"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Requests",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:935",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:936",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      },
+      {
+        "cards": {
+          "cardPadding": null,
+          "cardRound": null
+        },
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "max": null,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "gridPos": {
+          "h": 8,
+          "w": 24,
+          "x": 0,
+          "y": 6
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_service_handler_[[method]]_histogram_duration_bucket{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"}[1m]) -\r\n    min_over_time(tfs_service_handler_[[method]]_histogram_duration_bucket{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "1m",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "refId": "A"
+          }
+        ],
+        "timeFrom": null,
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "xBucketNumber": null,
+        "xBucketSize": null,
+        "yAxis": {
+          "decimals": null,
+          "format": "s",
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true,
+          "splitFactor": null
+        },
+        "yBucketBound": "auto",
+        "yBucketNumber": null,
+        "yBucketSize": null
+      },
+      {
+        "aliasColors": {},
+        "bars": false,
+        "dashLength": 10,
+        "dashes": false,
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "fill": 1,
+        "fillGradient": 0,
+        "gridPos": {
+          "h": 6,
+          "w": 24,
+          "x": 0,
+          "y": 14
+        },
+        "hiddenSeries": false,
+        "id": 5,
+        "legend": {
+          "alignAsTable": false,
+          "avg": false,
+          "current": false,
+          "max": false,
+          "min": false,
+          "rightSide": false,
+          "show": false,
+          "total": false,
+          "values": false
+        },
+        "lines": true,
+        "linewidth": 1,
+        "nullPointMode": "null",
+        "options": {
+          "alertThreshold": true
+        },
+        "percentage": false,
+        "pluginVersion": "7.5.4",
+        "pointradius": 2,
+        "points": false,
+        "renderer": "flot",
+        "seriesOverrides": [],
+        "spaceLength": 10,
+        "stack": false,
+        "steppedLine": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(tfs_service_handler_[[method]]_histogram_duration_sum{handler=~\"[[handler]]\", pod=~\"serviceservice-[[pod]]\"})",
+            "hide": false,
+            "interval": "",
+            "legendFormat": "total time",
+            "refId": "B"
+          }
+        ],
+        "thresholds": [],
+        "timeFrom": null,
+        "timeRegions": [],
+        "timeShift": null,
+        "title": "Total Exec Time",
+        "tooltip": {
+          "shared": true,
+          "sort": 0,
+          "value_type": "individual"
+        },
+        "transformations": [],
+        "type": "graph",
+        "xaxis": {
+          "buckets": null,
+          "mode": "time",
+          "name": null,
+          "show": true,
+          "values": []
+        },
+        "yaxes": [
+          {
+            "$$hashKey": "object:407",
+            "format": "s",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": "0",
+            "show": true
+          },
+          {
+            "$$hashKey": "object:408",
+            "format": "short",
+            "label": null,
+            "logBase": 1,
+            "max": null,
+            "min": null,
+            "show": true
+          }
+        ],
+        "yaxis": {
+          "align": false,
+          "alignLevel": null
+        }
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 27,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": "",
+          "current": {
+            "selected": false,
+            "text": "setendpoint",
+            "value": "setendpoint"
+          },
+          "datasource": "prometheus",
+          "definition": "metrics(tfs_service_handler_.+)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": false,
+          "label": "Method",
+          "multi": false,
+          "name": "method",
+          "options": [],
+          "query": {
+            "query": "metrics(tfs_service_handler_.+)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/tfs_service_handler_(.+)_histogram_duration_bucket/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, handler)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Handler",
+          "multi": true,
+          "name": "handler",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, handler)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, pod)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_service_handler_[[method]]_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "/serviceservice-(.*)/",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / Service / Handler",
+    "uid": "tfs-svc-hdlr",
+    "version": 16
+  }
+}
diff --git a/src/webui/old/grafana_prom_device_config_exec_details.json b/src/webui/old/grafana_prom_device_config_exec_details.json
new file mode 100644
index 0000000000000000000000000000000000000000..4b29a8dcaa99d0527e188790c2a1ff9ca000738a
--- /dev/null
+++ b/src/webui/old/grafana_prom_device_config_exec_details.json
@@ -0,0 +1,184 @@
+{"overwrite": true, "folderId": 0, "dashboard":
+  {
+    "annotations": {
+      "list": [
+        {
+          "builtIn": 1,
+          "datasource": "-- Grafana --",
+          "enable": true,
+          "hide": true,
+          "iconColor": "rgba(0, 211, 255, 1)",
+          "name": "Annotations & Alerts",
+          "type": "dashboard"
+        }
+      ]
+    },
+    "editable": true,
+    "gnetId": null,
+    "graphTooltip": 0,
+    "id": null,
+    "iteration": 1682003744753,
+    "links": [],
+    "panels": [
+      {
+        "cards": {
+          "cardPadding": null,
+          "cardRound": null
+        },
+        "color": {
+          "cardColor": "#b4ff00",
+          "colorScale": "linear",
+          "colorScheme": "interpolateRdYlGn",
+          "exponent": 0.5,
+          "max": null,
+          "min": 0,
+          "mode": "opacity"
+        },
+        "dataFormat": "tsbuckets",
+        "datasource": "prometheus",
+        "fieldConfig": {
+          "defaults": {},
+          "overrides": []
+        },
+        "gridPos": {
+          "h": 22,
+          "w": 24,
+          "x": 0,
+          "y": 0
+        },
+        "heatmap": {},
+        "hideZeroBuckets": true,
+        "highlightCards": true,
+        "id": 2,
+        "interval": "60s",
+        "legend": {
+          "show": true
+        },
+        "pluginVersion": "7.5.4",
+        "reverseYBuckets": false,
+        "targets": [
+          {
+            "exemplar": true,
+            "expr": "sum(\r\n    max_over_time(tfs_device_exec_details_configuredevice_histogram_duration_bucket{pod=~\"[[pod]]\", step_name=~\"[[step_name]]\"}[1m]) -\r\n    min_over_time(tfs_device_exec_details_configuredevice_histogram_duration_bucket{pod=~\"[[pod]]\", step_name=~\"[[step_name]]\"}[1m])\r\n) by (le)",
+            "format": "heatmap",
+            "instant": false,
+            "interval": "1m",
+            "intervalFactor": 1,
+            "legendFormat": "{{le}}",
+            "refId": "A"
+          }
+        ],
+        "title": "Histogram",
+        "tooltip": {
+          "show": true,
+          "showHistogram": true
+        },
+        "type": "heatmap",
+        "xAxis": {
+          "show": true
+        },
+        "xBucketNumber": null,
+        "xBucketSize": null,
+        "yAxis": {
+          "decimals": null,
+          "format": "s",
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true,
+          "splitFactor": null
+        },
+        "yBucketBound": "auto",
+        "yBucketNumber": null,
+        "yBucketSize": null
+      }
+    ],
+    "refresh": "5s",
+    "schemaVersion": 27,
+    "style": "dark",
+    "tags": [],
+    "templating": {
+      "list": [
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, pod)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Pod",
+          "multi": true,
+          "name": "pod",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, pod)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        },
+        {
+          "allValue": ".*",
+          "current": {
+            "selected": true,
+            "text": [
+              "All"
+            ],
+            "value": [
+              "$__all"
+            ]
+          },
+          "datasource": "prometheus",
+          "definition": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, step_name)",
+          "description": null,
+          "error": null,
+          "hide": 0,
+          "includeAll": true,
+          "label": "Step Name",
+          "multi": true,
+          "name": "step_name",
+          "options": [],
+          "query": {
+            "query": "label_values(tfs_device_exec_details_configuredevice_histogram_duration_bucket, step_name)",
+            "refId": "StandardVariableQuery"
+          },
+          "refresh": 2,
+          "regex": "",
+          "skipUrlSync": false,
+          "sort": 0,
+          "tagValuesQuery": "",
+          "tags": [],
+          "tagsQuery": "",
+          "type": "query",
+          "useTags": false
+        }
+      ]
+    },
+    "time": {
+      "from": "now-15m",
+      "to": "now"
+    },
+    "timepicker": {},
+    "timezone": "",
+    "title": "TFS / ConfigureDevice Details",
+    "uid": "tfs-dev-confdev",
+    "version": 4
+  }
+}
diff --git a/src/webui/service/__init__.py b/src/webui/service/__init__.py
index fca1071419b3b2b61739c2a0d1d8bfa45aba5119..e7f50ed42d19921b3423617f6860b5630e93adba 100644
--- a/src/webui/service/__init__.py
+++ b/src/webui/service/__init__.py
@@ -95,6 +95,9 @@ def create_app(use_config=None, web_app_root=None):
     from webui.service.link.routes import link              # pylint: disable=import-outside-toplevel
     app.register_blueprint(link)
 
+    from webui.service.policy.routes import policy          # pylint: disable=import-outside-toplevel
+    app.register_blueprint(policy)
+
     app.jinja_env.globals.update({              # pylint: disable=no-member
         'enumerate'           : enumerate,
         'json_to_list'        : json_to_list,
diff --git a/src/webui/service/link/routes.py b/src/webui/service/link/routes.py
index 0fda8958e2ab2609969d2c1f68aaae61b7360b68..3ab320d8b13d037e195f00ced9eb63bd14ecc0dd 100644
--- a/src/webui/service/link/routes.py
+++ b/src/webui/service/link/routes.py
@@ -13,8 +13,8 @@
 # limitations under the License.
 
 
-from flask import render_template, Blueprint, flash, session, redirect, url_for
-from common.proto.context_pb2 import Empty, Link, LinkList
+from flask import current_app, render_template, Blueprint, flash, session, redirect, url_for
+from common.proto.context_pb2 import Empty, Link, LinkId, LinkList
 from common.tools.context_queries.EndPoint import get_endpoint_names
 from common.tools.context_queries.Link import get_link
 from common.tools.context_queries.Topology import get_topology
@@ -65,3 +65,25 @@ def detail(link_uuid: str):
         device_names, endpoints_data = get_endpoint_names(context_client, link_obj.link_endpoint_ids)
     context_client.close()
     return render_template('link/detail.html',link=link_obj, device_names=device_names, endpoints_data=endpoints_data)
+
+@link.get('<path:link_uuid>/delete')
+def delete(link_uuid):
+    try:
+
+        # first, check if link exists!
+        # request: LinkId = LinkId()
+        # request.link_uuid.uuid = link_uuid
+        # response: Link = client.GetLink(request)
+        # TODO: finalize implementation
+
+        request = LinkId()
+        request.link_uuid.uuid = link_uuid # pylint: disable=no-member
+        context_client.connect()
+        context_client.RemoveLink(request)
+        context_client.close()
+
+        flash(f'Link "{link_uuid}" deleted successfully!', 'success')
+    except Exception as e: # pylint: disable=broad-except
+        flash(f'Problem deleting link "{link_uuid}": {e.details()}', 'danger')
+        current_app.logger.exception(e)
+    return redirect(url_for('link.home'))
diff --git a/src/webui/service/load_gen/forms.py b/src/webui/service/load_gen/forms.py
index 4e0020b04f33152de382f5b93af9735f8d737f92..4c5c095cd0ca7b0549a14be394e517694d9b3268 100644
--- a/src/webui/service/load_gen/forms.py
+++ b/src/webui/service/load_gen/forms.py
@@ -14,11 +14,19 @@
 
 from flask_wtf import FlaskForm
 from wtforms import BooleanField, FloatField, IntegerField, StringField, SubmitField
-from wtforms.validators import DataRequired, NumberRange
+from wtforms.validators import DataRequired, NumberRange, Regexp
+from load_generator.tools.ListScalarRange import RE_SCALAR_RANGE_LIST
+
+DEFAULT_AVAILABILITY   = '0.0..99.9999'
+DEFAULT_CAPACITY_GBPS  = '0.1..100.00' #'10, 40, 50, 100, 400'
+DEFAULT_E2E_LATENCY_MS = '5.0..100.00'
+
+DEFAULT_REGEX = r'.+'
 
 class LoadGenForm(FlaskForm):
     num_requests = IntegerField('Num Requests', default=100, validators=[DataRequired(), NumberRange(min=0)])
     num_generated = IntegerField('Num Generated', default=0, render_kw={'readonly': True})
+    num_released = IntegerField('Num Released', default=0, render_kw={'readonly': True})
 
     request_type_service_l2nm = BooleanField('Service L2NM', default=False)
     request_type_service_l3nm = BooleanField('Service L3NM', default=False)
@@ -27,10 +35,19 @@ class LoadGenForm(FlaskForm):
     request_type_slice_l2nm = BooleanField('Slice L2NM', default=True)
     request_type_slice_l3nm = BooleanField('Slice L3NM', default=False)
 
+    device_regex = StringField('Device selector [regex]', default=DEFAULT_REGEX)
+    endpoint_regex = StringField('Endpoint selector [regex]', default=DEFAULT_REGEX)
+
     offered_load = FloatField('Offered Load [Erlang]', default=50, validators=[NumberRange(min=0.0)])
     holding_time = FloatField('Holding Time [seconds]', default=10, validators=[NumberRange(min=0.0)])
     inter_arrival_time = FloatField('Inter Arrival Time [seconds]', default=0, validators=[NumberRange(min=0.0)])
 
+    availability   = StringField('Availability [%]', default=DEFAULT_AVAILABILITY,   validators=[Regexp(RE_SCALAR_RANGE_LIST)])
+    capacity_gbps  = StringField('Capacity [Gbps]',  default=DEFAULT_CAPACITY_GBPS,  validators=[Regexp(RE_SCALAR_RANGE_LIST)])
+    e2e_latency_ms = StringField('E2E Latency [ms]', default=DEFAULT_E2E_LATENCY_MS, validators=[Regexp(RE_SCALAR_RANGE_LIST)])
+
+    max_workers = IntegerField('Max Workers', default=10, validators=[DataRequired(), NumberRange(min=1)])
+
     do_teardown = BooleanField('Do Teardown', default=True)
 
     record_to_dlt = BooleanField('Record to DLT', default=False)
diff --git a/src/webui/service/load_gen/routes.py b/src/webui/service/load_gen/routes.py
index 5f47f06b0ff59ad1383aab94caa41adc08440c87..3483c2a65d08f3da18b2f630dbf7a59ac0f22ecb 100644
--- a/src/webui/service/load_gen/routes.py
+++ b/src/webui/service/load_gen/routes.py
@@ -17,6 +17,8 @@ from flask import redirect, render_template, Blueprint, flash, url_for
 from common.proto.context_pb2 import Empty
 from common.proto.load_generator_pb2 import Parameters, RequestTypeEnum
 from load_generator.client.LoadGeneratorClient import LoadGeneratorClient
+from load_generator.tools.ListScalarRange import (
+    list_scalar_range__grpc_to_str, list_scalar_range__list_to_grpc, parse_list_scalar_range)
 from .forms import LoadGenForm
 
 load_gen = Blueprint('load_gen', __name__, url_prefix='/load_gen')
@@ -55,23 +57,34 @@ def home():
     _holding_time       = round(status.parameters.holding_time       , ndigits=4)
     _inter_arrival_time = round(status.parameters.inter_arrival_time , ndigits=4)
 
+    _availability       = list_scalar_range__grpc_to_str(status.parameters.availability  )
+    _capacity_gbps      = list_scalar_range__grpc_to_str(status.parameters.capacity_gbps )
+    _e2e_latency_ms     = list_scalar_range__grpc_to_str(status.parameters.e2e_latency_ms)
+
     form = LoadGenForm()
-    set_properties(form.num_requests             , status.parameters.num_requests , readonly=status.running)
-    set_properties(form.offered_load             , _offered_load                  , readonly=status.running)
-    set_properties(form.holding_time             , _holding_time                  , readonly=status.running)
-    set_properties(form.inter_arrival_time       , _inter_arrival_time            , readonly=status.running)
-    set_properties(form.do_teardown              , status.parameters.do_teardown  , disabled=status.running)
-    set_properties(form.record_to_dlt            , status.parameters.record_to_dlt, disabled=status.running)
-    set_properties(form.dlt_domain_id            , status.parameters.dlt_domain_id, readonly=status.running)
-    set_properties(form.request_type_service_l2nm, _request_type_service_l2nm     , disabled=status.running)
-    set_properties(form.request_type_service_l3nm, _request_type_service_l3nm     , disabled=status.running)
-    set_properties(form.request_type_service_mw  , _request_type_service_mw       , disabled=status.running)
-    set_properties(form.request_type_service_tapi, _request_type_service_tapi     , disabled=status.running)
-    set_properties(form.request_type_slice_l2nm  , _request_type_slice_l2nm       , disabled=status.running)
-    set_properties(form.request_type_slice_l3nm  , _request_type_slice_l3nm       , disabled=status.running)
-    set_properties(form.num_generated            , status.num_generated           , disabled=True)
-    set_properties(form.infinite_loop            , status.infinite_loop           , disabled=True)
-    set_properties(form.running                  , status.running                 , disabled=True)
+    set_properties(form.num_requests             , status.parameters.num_requests  , readonly=status.running)
+    set_properties(form.device_regex             , status.parameters.device_regex  , readonly=status.running)
+    set_properties(form.endpoint_regex           , status.parameters.endpoint_regex, readonly=status.running)
+    set_properties(form.offered_load             , _offered_load                   , readonly=status.running)
+    set_properties(form.holding_time             , _holding_time                   , readonly=status.running)
+    set_properties(form.inter_arrival_time       , _inter_arrival_time             , readonly=status.running)
+    set_properties(form.availability             , _availability                   , readonly=status.running)
+    set_properties(form.capacity_gbps            , _capacity_gbps                  , readonly=status.running)
+    set_properties(form.e2e_latency_ms           , _e2e_latency_ms                 , readonly=status.running)
+    set_properties(form.max_workers              , status.parameters.max_workers   , readonly=status.running)
+    set_properties(form.do_teardown              , status.parameters.do_teardown   , disabled=status.running)
+    set_properties(form.record_to_dlt            , status.parameters.record_to_dlt , disabled=status.running)
+    set_properties(form.dlt_domain_id            , status.parameters.dlt_domain_id , readonly=status.running)
+    set_properties(form.request_type_service_l2nm, _request_type_service_l2nm      , disabled=status.running)
+    set_properties(form.request_type_service_l3nm, _request_type_service_l3nm      , disabled=status.running)
+    set_properties(form.request_type_service_mw  , _request_type_service_mw        , disabled=status.running)
+    set_properties(form.request_type_service_tapi, _request_type_service_tapi      , disabled=status.running)
+    set_properties(form.request_type_slice_l2nm  , _request_type_slice_l2nm        , disabled=status.running)
+    set_properties(form.request_type_slice_l3nm  , _request_type_slice_l3nm        , disabled=status.running)
+    set_properties(form.num_generated            , status.num_generated            , disabled=True)
+    set_properties(form.num_released             , status.num_released             , disabled=True)
+    set_properties(form.infinite_loop            , status.infinite_loop            , disabled=True)
+    set_properties(form.running                  , status.running                  , disabled=True)
 
     form.submit.label.text = 'Stop' if status.running else 'Start'
     form_action = url_for('load_gen.stop') if status.running else url_for('load_gen.start')
@@ -82,16 +95,27 @@ def start():
     form = LoadGenForm()
     if form.validate_on_submit():
         try:
+            _availability   = parse_list_scalar_range(form.availability.data  )
+            _capacity_gbps  = parse_list_scalar_range(form.capacity_gbps.data )
+            _e2e_latency_ms = parse_list_scalar_range(form.e2e_latency_ms.data)
+
             load_gen_params = Parameters()
             load_gen_params.num_requests       = form.num_requests.data
+            load_gen_params.device_regex       = form.device_regex.data
+            load_gen_params.endpoint_regex     = form.endpoint_regex.data
             load_gen_params.offered_load       = form.offered_load.data
             load_gen_params.holding_time       = form.holding_time.data
             load_gen_params.inter_arrival_time = form.inter_arrival_time.data
+            load_gen_params.max_workers        = form.max_workers.data
             load_gen_params.do_teardown        = form.do_teardown.data
             load_gen_params.dry_mode           = False
             load_gen_params.record_to_dlt      = form.record_to_dlt.data
             load_gen_params.dlt_domain_id      = form.dlt_domain_id.data
 
+            list_scalar_range__list_to_grpc(_availability,   load_gen_params.availability  ) # pylint: disable=no-member
+            list_scalar_range__list_to_grpc(_capacity_gbps,  load_gen_params.capacity_gbps ) # pylint: disable=no-member
+            list_scalar_range__list_to_grpc(_e2e_latency_ms, load_gen_params.e2e_latency_ms) # pylint: disable=no-member
+
             del load_gen_params.request_types[:] # pylint: disable=no-member
             request_types = list()
             if form.request_type_service_l2nm.data: request_types.append(RequestTypeEnum.REQUESTTYPE_SERVICE_L2NM)
diff --git a/src/webui/service/policy/__init__.py b/src/webui/service/policy/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..1549d9811aa5d1c193a44ad45d0d7773236c0612
--- /dev/null
+++ b/src/webui/service/policy/__init__.py
@@ -0,0 +1,14 @@
+# 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.
+
diff --git a/src/webui/service/policy/routes.py b/src/webui/service/policy/routes.py
new file mode 100644
index 0000000000000000000000000000000000000000..6d14f86b4f1428695b474b3f2e2dd4dc72657452
--- /dev/null
+++ b/src/webui/service/policy/routes.py
@@ -0,0 +1,50 @@
+# 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.
+
+import grpc
+from flask import render_template, Blueprint
+from common.proto.context_pb2 import Empty
+from common.proto.policy_pb2 import PolicyRuleStateEnum
+from context.client.ContextClient import ContextClient
+
+policy = Blueprint('policy', __name__, url_prefix='/policy')
+
+context_client = ContextClient()
+
+@policy.get('/')
+def home():
+    context_client.connect()
+    policy_rules = context_client.ListPolicyRules(Empty())
+    policy_rules = policy_rules.policyRules
+    context_client.close()
+    return render_template('policy/home.html', policy_rules=policy_rules, prse=PolicyRuleStateEnum)
+
+#@policy.get('<path:policy_uuid>/detail')
+#def detail(policy_uuid: str):
+#    try:
+#        context_client.connect()
+#
+#        slice_obj = get_slice_by_uuid(context_client, slice_uuid, rw_copy=False)
+#        if slice_obj is None:
+#            flash('Context({:s})/Slice({:s}) not found'.format(str(context_uuid), str(slice_uuid)), 'danger')
+#            slice_obj = Slice()
+#
+#        context_client.close()
+#
+#        return render_template(
+#            'slice/detail.html', slice=slice_obj, prse=PolicyRuleStateEnum)
+#    except Exception as e:
+#        flash('The system encountered an error and cannot show the details of this slice.', 'warning')
+#        current_app.logger.exception(e)
+#        return redirect(url_for('slice.home'))
diff --git a/src/webui/service/templates/base.html b/src/webui/service/templates/base.html
index 1dfa3687198d8a33db346ba2bbcd2989f6f109bb..61c283b0d957b4d13b7cc57e47d3ea2675ab76f0 100644
--- a/src/webui/service/templates/base.html
+++ b/src/webui/service/templates/base.html
@@ -83,6 +83,13 @@
                   <a class="nav-link" href="{{ url_for('slice.home') }}">Slice</a>
                   {% endif %}
                 </li>
+                <li class="nav-item">
+                  {% if '/policy/' in request.path %}
+                  <a class="nav-link active" aria-current="page" href="{{ url_for('policy.home') }}">Policy</a>
+                  {% else %}
+                  <a class="nav-link" href="{{ url_for('policy.home') }}">Policy</a>
+                  {% endif %}
+                </li>
                 <li class="nav-item">
                   <a class="nav-link" href="/grafana" id="grafana_link" target="grafana">Grafana</a>
                 </li>
diff --git a/src/webui/service/templates/link/detail.html b/src/webui/service/templates/link/detail.html
index 916abafde05b3ec990346ff7966f207b1dafc10a..8ca7faee3e1871d11b819c6ca95668e654041f8c 100644
--- a/src/webui/service/templates/link/detail.html
+++ b/src/webui/service/templates/link/detail.html
@@ -13,62 +13,92 @@
     See the License for the specific language governing permissions and
     limitations under the License.
    -->
-   {% extends 'base.html' %}
-   
-   {% block content %}
-    <h1>Link {{ link.name }} ({{ link.link_id.link_uuid.uuid }})</h1>
-    <div class="row mb-3">
-          <div class="col-sm-3">
-               <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('link.home') }}'">
-                    <i class="bi bi-box-arrow-in-left"></i>
-                    Back to link list
-               </button>
-          </div>
-     </div>
 
-     <br>
-       <div class="row mb-3">
-            <div class="col-sm-4">
-               <b>UUID: </b>{{ link.link_id.link_uuid.uuid }}<br>
-               <b>Name: </b>{{ link.name }}<br>
-           </div>
-            <div class="col-sm-8">
-                    <table class="table table-striped table-hover">
-                        <thead>
-                            <tr>
-                                <th scope="col">Endpoint UUID</th>
-                                <th scope="col">Name</th>
-                                <th scope="col">Device</th>
-                                <th scope="col">Endpoint Type</th>
-                            </tr>
-                        </thead>
-                        <tbody>
-                              {% for endpoint in link.link_endpoint_ids %}
-                              <tr>
-                                   <td>
-                                        {{ endpoint.endpoint_uuid.uuid }}
-                                   </td>
-                                   <td>
-                                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }}
-                                   </td>
-                                   <td>
-                                        <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}">
-                                             {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }}
-                                             <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
-                                                 <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
-                                                 <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
-                                             </svg>
-                                        </a>
-                                   </td>
-                                   <td>
-                                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }}
-                                   </td>
-                              </tr>
-                              {% endfor %}
-                        </tbody>
-                    </table>
+{% extends 'base.html' %}
+
+{% block content %}
+<h1>Link {{ link.name }} ({{ link.link_id.link_uuid.uuid }})</h1>
+<div class="row mb-3">
+    <div class="col-sm-3">
+        <button type="button" class="btn btn-success" onclick="window.location.href='{{ url_for('link.home') }}'">
+            <i class="bi bi-box-arrow-in-left"></i>
+            Back to link list
+        </button>
+    </div>
+    <div class="col-sm-3">
+        <!-- <button type="button" class="btn btn-danger"><i class="bi bi-x-square"></i>Delete link</button> -->
+        <button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
+            <i class="bi bi-x-square"></i>
+            Delete link
+        </button>
+    </div>
+</div>
+
+<br>
+<div class="row mb-3">
+    <div class="col-sm-4">
+        <b>UUID: </b>{{ link.link_id.link_uuid.uuid }}<br>
+        <b>Name: </b>{{ link.name }}<br>
+    </div>
+    <div class="col-sm-8">
+        <table class="table table-striped table-hover">
+            <thead>
+                <tr>
+                    <th scope="col">Endpoint UUID</th>
+                    <th scope="col">Name</th>
+                    <th scope="col">Device</th>
+                    <th scope="col">Endpoint Type</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for endpoint in link.link_endpoint_ids %}
+                <tr>
+                    <td>
+                        {{ endpoint.endpoint_uuid.uuid }}
+                    </td>
+                    <td>
+                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, (endpoint.endpoint_uuid.uuid, ''))[0] }}
+                    </td>
+                    <td>
+                        <a href="{{ url_for('device.detail', device_uuid=endpoint.device_id.device_uuid.uuid) }}">
+                            {{ device_names.get(endpoint.device_id.device_uuid.uuid, endpoint.device_id.device_uuid.uuid) }}
+                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
+                                    <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
+                                    <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
+                            </svg>
+                        </a>
+                    </td>
+                    <td>
+                        {{ endpoints_data.get(endpoint.endpoint_uuid.uuid, ('', '-'))[1] }}
+                    </td>
+                </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+</div>
+
+
+<!-- Modal -->
+<div class="modal fade" id="deleteModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
+    aria-labelledby="staticBackdropLabel" aria-hidden="true">
+    <div class="modal-dialog">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title" id="staticBackdropLabel">Delete link?</h5>
+                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+            </div>
+            <div class="modal-body">
+                Are you sure you want to delete the link "{{ link.link_id.link_uuid.uuid }}"?
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">No</button>
+                <a type="button" class="btn btn-danger"
+                    href="{{ url_for('link.delete', link_uuid=link.link_id.link_uuid.uuid) }}"><i
+                        class="bi bi-exclamation-diamond"></i>Yes</a>
             </div>
         </div>
+    </div>
+</div>
 
-   {% endblock %}
-   
\ No newline at end of file
+{% endblock %}
diff --git a/src/webui/service/templates/load_gen/home.html b/src/webui/service/templates/load_gen/home.html
index d58f42601925ca438ab9d9f20b32f94960b5cada..cec0a38dba2b4b31d4d07d391e4ce211f0c7ac76 100644
--- a/src/webui/service/templates/load_gen/home.html
+++ b/src/webui/service/templates/load_gen/home.html
@@ -53,6 +53,21 @@
             </div>
             <br />
 
+            <div class="row mb-3">
+                {{ form.num_released.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.num_released.errors %}
+                        {{ form.num_released(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.num_released.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.num_released(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
             <div class="row mb-3">
                 <div class="col-sm-2 col-form-label">Service Types:</div>
                 <div class="col-sm-10">
@@ -68,6 +83,36 @@
             </div>
             <br />
 
+            <div class="row mb-3">
+                {{ form.device_regex.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.device_regex.errors %}
+                        {{ form.device_regex(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.device_regex.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.device_regex(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
+            <div class="row mb-3">
+                {{ form.endpoint_regex.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.endpoint_regex.errors %}
+                        {{ form.endpoint_regex(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.endpoint_regex.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.endpoint_regex(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
             <div class="row mb-3">
                 {{ form.offered_load.label(class="col-sm-2 col-form-label") }}
                 <div class="col-sm-10">
@@ -113,6 +158,66 @@
             </div>
             <br />
 
+            <div class="row mb-3">
+                {{ form.availability.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.availability.errors %}
+                        {{ form.availability(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.availability.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.availability(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
+            <div class="row mb-3">
+                {{ form.capacity_gbps.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.capacity_gbps.errors %}
+                        {{ form.capacity_gbps(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.capacity_gbps.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.capacity_gbps(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
+            <div class="row mb-3">
+                {{ form.e2e_latency_ms.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.e2e_latency_ms.errors %}
+                        {{ form.e2e_latency_ms(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.e2e_latency_ms.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.e2e_latency_ms(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
+            <div class="row mb-3">
+                {{ form.max_workers.label(class="col-sm-2 col-form-label") }}
+                <div class="col-sm-10">
+                    {% if form.max_workers.errors %}
+                        {{ form.max_workers(class="form-control is-invalid") }}
+                        <div class="invalid-feedback">
+                            {% for error in form.max_workers.errors %}<span>{{ error }}</span>{% endfor %}
+                        </div>
+                    {% else %}
+                        {{ form.max_workers(class="form-control") }}
+                    {% endif %}
+                </div>
+            </div>
+            <br />
+
             <div class="row mb-3">
                 <div class="col-sm-10">
                     {{ form.do_teardown }} {{ form.do_teardown.label(class="col-sm-3 col-form-label") }}<br/>
diff --git a/src/webui/service/templates/policy/home.html b/src/webui/service/templates/policy/home.html
new file mode 100644
index 0000000000000000000000000000000000000000..081a7f0b5291346633a2f682ba4552b5c1e362fb
--- /dev/null
+++ b/src/webui/service/templates/policy/home.html
@@ -0,0 +1,84 @@
+<!--
+ 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.
+-->
+
+{% extends 'base.html' %}
+
+{% block content %}
+    <h1>Policy</h1>
+
+    <div class="row">
+        <div class="col">
+            {{ policies | length }} policies found in context <i>{{ session['context_uuid'] }}</i>
+        </div>
+    </div>
+
+    <table class="table table-striped table-hover">
+        <thead>
+          <tr>
+            <th scope="col">UUID</th>
+            <th scope="col">Kind</th>
+            <th scope="col">Priority</th>
+            <th scope="col">Condition</th>
+            <th scope="col">Operator</th>
+            <th scope="col">Action</th>
+            <th scope="col">Service</th>
+            <th scope="col">Devices</th>
+            <th scope="col">State</th>
+            <th scope="col">Message</th>
+            <th scope="col">Extra</th>
+            <th scope="col"></th>
+          </tr>
+        </thead>
+        <tbody>
+            {% if policies %}
+                {% for policy in policies %}
+                    {% if policy.WhichOneof('policy_rule') == 'device' %}
+                        <tr>
+                            <td>{{ policy.device.policyRuleBasic.policyRuleId.uuid }}</td>
+                            <td>{{ policy.WhichOneof('policy_rule') }}</td>
+                            <td>{{ policy.device.policyRuleBasic.priority }}</td>
+                            <td>{{ policy.device.policyRuleBasic.conditionList }}</td>
+                            <td>{{ policy.device.policyRuleBasic.booleanOperator }}</td>
+                            <td>{{ policy.device.policyRuleBasic.actionList }}</td>
+                            <td>-</td>
+                            <td>{{ policy.device.deviceList }}</td>
+                            <td>{{ prse.Name(policy.device.policyRuleBasic.policyRuleState.policyRuleState).replace('POLICY_', '') }}</td>
+                            <td>{{ policy.device.policyRuleBasic.policyRuleState.policyRuleStateMessage }}</td>
+                        </tr>
+                    {% elif policy.WhichOneof('policy_rule') == 'service' %}
+                        <tr>
+                            <td>{{ policy.service.policyRuleBasic.policyRuleId.uuid }}</td>
+                            <td>{{ policy.WhichOneof('policy_rule') }}</td>
+                            <td>{{ policy.service.policyRuleBasic.priority }}</td>
+                            <td>{{ policy.service.policyRuleBasic.conditionList }}</td>
+                            <td>{{ policy.service.policyRuleBasic.booleanOperator }}</td>
+                            <td>{{ policy.service.policyRuleBasic.actionList }}</td>
+                            <td>{{ policy.service.serviceId }}</td>
+                            <td>{{ policy.service.deviceList }}</td>
+                            <td>{{ prse.Name(policy.service.policyRuleBasic.policyRuleState.policyRuleState).replace('POLICY_', '') }}</td>
+                            <td>{{ policy.service.policyRuleBasic.policyRuleState.policyRuleStateMessage }}</td>
+                        </tr>
+                    {% else %}
+                        <tr><td colspan="11">Unsupported policy type {{ policy.WhichOneof('policy_rule') }}</td></tr>
+                    {% endif %}
+                {% endfor %}
+            {% else %}
+                <tr><td colspan="11">No policies found</td></tr>
+            {% endif %}
+        </tbody>
+    </table>
+
+{% endblock %}