From 102d990ccbb810758a92cf4eac7e808cbd30f880 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 27 Apr 2023 15:39:23 +0000 Subject: [PATCH 1/3] Protos: - extend load generator with device and endpoint regex selectors --- proto/load_generator.proto | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/proto/load_generator.proto b/proto/load_generator.proto index 7d0070c66..32523b331 100644 --- a/proto/load_generator.proto +++ b/proto/load_generator.proto @@ -48,17 +48,19 @@ message ScalarOrRange { 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; - repeated ScalarOrRange availability = 6; // one from the list is selected - repeated ScalarOrRange capacity_gbps = 7; // one from the list is selected - repeated ScalarOrRange e2e_latency_ms = 8; // one from the list is selected - uint32 max_workers = 9; - bool do_teardown = 10; - bool dry_mode = 11; - bool record_to_dlt = 12; - string dlt_domain_id = 13; + 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 { -- GitLab From 60b0965668895c45982211a6bbcb29c6d04499a1 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 27 Apr 2023 16:15:09 +0000 Subject: [PATCH 2/3] Load Generator component: - Added logic to filter src/dst candidate device and endpoint - Corrected DLT recording logic --- src/load_generator/command/__main__.py | 2 ++ src/load_generator/load_gen/Parameters.py | 25 ++++++++++++++++--- .../load_gen/RequestGenerator.py | 17 ++++++++----- .../LoadGeneratorServiceServicerImpl.py | 4 +++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/load_generator/command/__main__.py b/src/load_generator/command/__main__.py index a97f081a3..4fa2094e0 100644 --- a/src/load_generator/command/__main__.py +++ b/src/load_generator/command/__main__.py @@ -34,6 +34,8 @@ 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]], diff --git a/src/load_generator/load_gen/Parameters.py b/src/load_generator/load_gen/Parameters.py index aca40cd38..5bb7a9b72 100644 --- a/src/load_generator/load_gen/Parameters.py +++ b/src/load_generator/load_gen/Parameters.py @@ -20,16 +20,27 @@ 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, + 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 + 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 @@ -62,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 diff --git a/src/load_generator/load_gen/RequestGenerator.py b/src/load_generator/load_gen/RequestGenerator.py index 3a52b3b32..974ce6f13 100644 --- a/src/load_generator/load_gen/RequestGenerator.py +++ b/src/load_generator/load_gen/RequestGenerator.py @@ -83,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) @@ -98,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 @@ -119,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: diff --git a/src/load_generator/service/LoadGeneratorServiceServicerImpl.py b/src/load_generator/service/LoadGeneratorServiceServicerImpl.py index 9f12f3492..866f9f089 100644 --- a/src/load_generator/service/LoadGeneratorServiceServicerImpl.py +++ b/src/load_generator/service/LoadGeneratorServiceServicerImpl.py @@ -37,6 +37,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer): self._parameters = LoadGen_Parameters( 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, @@ -79,6 +81,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer): 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 -- GitLab From ff7c68fead50f972fe4aa174078c9fcce56d31b1 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 27 Apr 2023 16:15:52 +0000 Subject: [PATCH 3/3] WebUI component: - Added fields in load generator tab to filter src/dst candidate device and endpoint --- src/webui/service/load_gen/forms.py | 5 ++ src/webui/service/load_gen/routes.py | 46 ++++++++++--------- .../service/templates/load_gen/home.html | 30 ++++++++++++ 3 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/webui/service/load_gen/forms.py b/src/webui/service/load_gen/forms.py index e0d11800c..4c5c095cd 100644 --- a/src/webui/service/load_gen/forms.py +++ b/src/webui/service/load_gen/forms.py @@ -21,6 +21,8 @@ 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}) @@ -33,6 +35,9 @@ 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)]) diff --git a/src/webui/service/load_gen/routes.py b/src/webui/service/load_gen/routes.py index f05f57f6d..3483c2a65 100644 --- a/src/webui/service/load_gen/routes.py +++ b/src/webui/service/load_gen/routes.py @@ -62,27 +62,29 @@ def home(): _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.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) + 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') @@ -99,6 +101,8 @@ def start(): 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 diff --git a/src/webui/service/templates/load_gen/home.html b/src/webui/service/templates/load_gen/home.html index 5bedf66fa..cec0a38db 100644 --- a/src/webui/service/templates/load_gen/home.html +++ b/src/webui/service/templates/load_gen/home.html @@ -83,6 +83,36 @@
+
+ {{ form.device_regex.label(class="col-sm-2 col-form-label") }} +
+ {% if form.device_regex.errors %} + {{ form.device_regex(class="form-control is-invalid") }} +
+ {% for error in form.device_regex.errors %}{{ error }}{% endfor %} +
+ {% else %} + {{ form.device_regex(class="form-control") }} + {% endif %} +
+
+
+ +
+ {{ form.endpoint_regex.label(class="col-sm-2 col-form-label") }} +
+ {% if form.endpoint_regex.errors %} + {{ form.endpoint_regex(class="form-control is-invalid") }} +
+ {% for error in form.endpoint_regex.errors %}{{ error }}{% endfor %} +
+ {% else %} + {{ form.endpoint_regex(class="form-control") }} + {% endif %} +
+
+
+
{{ form.offered_load.label(class="col-sm-2 col-form-label") }}
-- GitLab