Skip to content
Snippets Groups Projects
Commit d2dc573e authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

Merge branch 'feat/load-gen-add-device-endpoint-selectors' into 'develop'

Load Generator: filter candidate src/dst devices and endpoints

See merge request !96
parents 51a32b58 ff7c68fe
No related branches found
No related tags found
2 merge requests!142Release TeraFlowSDN 2.1,!96Load Generator: filter candidate src/dst devices and endpoints
...@@ -48,17 +48,19 @@ message ScalarOrRange { ...@@ -48,17 +48,19 @@ message ScalarOrRange {
message Parameters { message Parameters {
uint64 num_requests = 1; // if == 0, generate infinite requests uint64 num_requests = 1; // if == 0, generate infinite requests
repeated RequestTypeEnum request_types = 2; repeated RequestTypeEnum request_types = 2;
float offered_load = 3; string device_regex = 3; // Only devices and endpoints matching the regex expression will be considered as
float holding_time = 4; string endpoint_regex = 4; // source-destination candidates for the requests generated.
float inter_arrival_time = 5; float offered_load = 5;
repeated ScalarOrRange availability = 6; // one from the list is selected float holding_time = 6;
repeated ScalarOrRange capacity_gbps = 7; // one from the list is selected float inter_arrival_time = 7;
repeated ScalarOrRange e2e_latency_ms = 8; // one from the list is selected repeated ScalarOrRange availability = 8; // One from the list is selected to populate the constraint
uint32 max_workers = 9; repeated ScalarOrRange capacity_gbps = 9; // One from the list is selected to populate the constraint
bool do_teardown = 10; repeated ScalarOrRange e2e_latency_ms = 10; // One from the list is selected to populate the constraint
bool dry_mode = 11; uint32 max_workers = 11;
bool record_to_dlt = 12; bool do_teardown = 12;
string dlt_domain_id = 13; bool dry_mode = 13;
bool record_to_dlt = 14;
string dlt_domain_id = 15;
} }
message Status { message Status {
......
...@@ -34,6 +34,8 @@ def main(): ...@@ -34,6 +34,8 @@ def main():
RequestType.SLICE_L2NM, RequestType.SLICE_L2NM,
RequestType.SLICE_L3NM, RequestType.SLICE_L3NM,
], ],
device_regex=r'.+',
endpoint_regex=r'.+',
offered_load = 50, offered_load = 50,
holding_time = 10, holding_time = 10,
availability_ranges = [[0.0, 99.9999]], availability_ranges = [[0.0, 99.9999]],
......
...@@ -20,16 +20,27 @@ from load_generator.tools.ListScalarRange import Type_ListScalarRange ...@@ -20,16 +20,27 @@ from load_generator.tools.ListScalarRange import Type_ListScalarRange
class Parameters: class Parameters:
def __init__( def __init__(
self, num_requests : int, request_types : List[str], offered_load : Optional[float] = None, self,
inter_arrival_time : Optional[float] = None, holding_time : Optional[float] = None, 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, availability_ranges : Type_ListScalarRange = DEFAULT_AVAILABILITY_RANGES,
capacity_gbps_ranges : Type_ListScalarRange = DEFAULT_CAPACITY_GBPS_RANGES, capacity_gbps_ranges : Type_ListScalarRange = DEFAULT_CAPACITY_GBPS_RANGES,
e2e_latency_ms_ranges : Type_ListScalarRange = DEFAULT_E2E_LATENCY_MS_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, max_workers : int = DEFAULT_MAX_WORKERS,
record_to_dlt : bool = False, dlt_domain_id : Optional[str] = None do_teardown : bool = True,
dry_mode : bool = False,
record_to_dlt : bool = False,
dlt_domain_id : Optional[str] = None
) -> None: ) -> None:
self._num_requests = num_requests self._num_requests = num_requests
self._request_types = request_types 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._offered_load = offered_load
self._inter_arrival_time = inter_arrival_time self._inter_arrival_time = inter_arrival_time
self._holding_time = holding_time self._holding_time = holding_time
...@@ -62,6 +73,12 @@ class Parameters: ...@@ -62,6 +73,12 @@ class Parameters:
@property @property
def request_types(self): return self._request_types 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 @property
def offered_load(self): return self._offered_load def offered_load(self): return self._offered_load
......
...@@ -83,13 +83,21 @@ class RequestGenerator: ...@@ -83,13 +83,21 @@ class RequestGenerator:
if self._parameters.record_to_dlt: if self._parameters.record_to_dlt:
dlt_domain_id = TopologyId(**json_topology_id('dlt-perf-eval')) 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()) devices = context_client.ListDevices(Empty())
for device in devices.devices: 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 device_uuid = device.device_id.device_uuid.uuid
self._device_data[device_uuid] = grpc_message_to_json(device) self._device_data[device_uuid] = grpc_message_to_json(device)
_endpoints = self._available_device_endpoints.setdefault(device_uuid, set()) _endpoints = self._available_device_endpoints.setdefault(device_uuid, set())
for endpoint in device.device_endpoints: for endpoint in device.device_endpoints:
if re_endpoint.match(endpoint.name) is None: continue
endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid
endpoints = self._device_endpoint_data.setdefault(device_uuid, dict()) endpoints = self._device_endpoint_data.setdefault(device_uuid, dict())
endpoints[endpoint_uuid] = grpc_message_to_json(endpoint) endpoints[endpoint_uuid] = grpc_message_to_json(endpoint)
...@@ -98,12 +106,12 @@ class RequestGenerator: ...@@ -98,12 +106,12 @@ class RequestGenerator:
_endpoints.add(endpoint_uuid) _endpoints.add(endpoint_uuid)
self._endpoint_ids_to_types.setdefault((device_uuid, endpoint_uuid), endpoint_type) 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)) 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()) links = context_client.ListLinks(Empty())
for link in links.links: 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: for endpoint_id in link.link_endpoint_ids:
device_uuid = endpoint_id.device_id.device_uuid.uuid device_uuid = endpoint_id.device_id.device_uuid.uuid
endpoint_uuid = endpoint_id.endpoint_uuid.uuid endpoint_uuid = endpoint_id.endpoint_uuid.uuid
...@@ -119,9 +127,6 @@ class RequestGenerator: ...@@ -119,9 +127,6 @@ class RequestGenerator:
endpoint_key = (device_uuid, endpoint_uuid) endpoint_key = (device_uuid, endpoint_uuid)
if endpoint_key not in endpoints_for_type: continue if endpoint_key not in endpoints_for_type: continue
endpoints_for_type.discard(endpoint_key) 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: def dump_state(self) -> None:
with self._lock: with self._lock:
......
...@@ -37,6 +37,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer): ...@@ -37,6 +37,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer):
self._parameters = LoadGen_Parameters( self._parameters = LoadGen_Parameters(
num_requests = request.num_requests, num_requests = request.num_requests,
request_types = [REQUEST_TYPE_MAP[rt] for rt in request.request_types], 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, 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, 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, inter_arrival_time = request.inter_arrival_time if request.inter_arrival_time > 1.e-12 else None,
...@@ -79,6 +81,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer): ...@@ -79,6 +81,8 @@ class LoadGeneratorServiceServicerImpl(LoadGeneratorServiceServicer):
stat_pars = status.parameters # 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.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.offered_load = params.offered_load # pylint: disable=no-member
stat_pars.holding_time = params.holding_time # 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.inter_arrival_time = params.inter_arrival_time # pylint: disable=no-member
......
...@@ -21,6 +21,8 @@ DEFAULT_AVAILABILITY = '0.0..99.9999' ...@@ -21,6 +21,8 @@ DEFAULT_AVAILABILITY = '0.0..99.9999'
DEFAULT_CAPACITY_GBPS = '0.1..100.00' #'10, 40, 50, 100, 400' DEFAULT_CAPACITY_GBPS = '0.1..100.00' #'10, 40, 50, 100, 400'
DEFAULT_E2E_LATENCY_MS = '5.0..100.00' DEFAULT_E2E_LATENCY_MS = '5.0..100.00'
DEFAULT_REGEX = r'.+'
class LoadGenForm(FlaskForm): class LoadGenForm(FlaskForm):
num_requests = IntegerField('Num Requests', default=100, validators=[DataRequired(), NumberRange(min=0)]) num_requests = IntegerField('Num Requests', default=100, validators=[DataRequired(), NumberRange(min=0)])
num_generated = IntegerField('Num Generated', default=0, render_kw={'readonly': True}) num_generated = IntegerField('Num Generated', default=0, render_kw={'readonly': True})
...@@ -33,6 +35,9 @@ class LoadGenForm(FlaskForm): ...@@ -33,6 +35,9 @@ class LoadGenForm(FlaskForm):
request_type_slice_l2nm = BooleanField('Slice L2NM', default=True) request_type_slice_l2nm = BooleanField('Slice L2NM', default=True)
request_type_slice_l3nm = BooleanField('Slice L3NM', default=False) 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)]) 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)]) 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)]) inter_arrival_time = FloatField('Inter Arrival Time [seconds]', default=0, validators=[NumberRange(min=0.0)])
......
...@@ -62,27 +62,29 @@ def home(): ...@@ -62,27 +62,29 @@ def home():
_e2e_latency_ms = list_scalar_range__grpc_to_str(status.parameters.e2e_latency_ms) _e2e_latency_ms = list_scalar_range__grpc_to_str(status.parameters.e2e_latency_ms)
form = LoadGenForm() form = LoadGenForm()
set_properties(form.num_requests , status.parameters.num_requests , readonly=status.running) 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.device_regex , status.parameters.device_regex , readonly=status.running)
set_properties(form.holding_time , _holding_time , readonly=status.running) set_properties(form.endpoint_regex , status.parameters.endpoint_regex, readonly=status.running)
set_properties(form.inter_arrival_time , _inter_arrival_time , readonly=status.running) set_properties(form.offered_load , _offered_load , readonly=status.running)
set_properties(form.availability , _availability , readonly=status.running) set_properties(form.holding_time , _holding_time , readonly=status.running)
set_properties(form.capacity_gbps , _capacity_gbps , readonly=status.running) set_properties(form.inter_arrival_time , _inter_arrival_time , readonly=status.running)
set_properties(form.e2e_latency_ms , _e2e_latency_ms , readonly=status.running) set_properties(form.availability , _availability , readonly=status.running)
set_properties(form.max_workers , status.parameters.max_workers , readonly=status.running) set_properties(form.capacity_gbps , _capacity_gbps , readonly=status.running)
set_properties(form.do_teardown , status.parameters.do_teardown , disabled=status.running) set_properties(form.e2e_latency_ms , _e2e_latency_ms , readonly=status.running)
set_properties(form.record_to_dlt , status.parameters.record_to_dlt, disabled=status.running) set_properties(form.max_workers , status.parameters.max_workers , readonly=status.running)
set_properties(form.dlt_domain_id , status.parameters.dlt_domain_id, readonly=status.running) set_properties(form.do_teardown , status.parameters.do_teardown , disabled=status.running)
set_properties(form.request_type_service_l2nm, _request_type_service_l2nm , disabled=status.running) set_properties(form.record_to_dlt , status.parameters.record_to_dlt , disabled=status.running)
set_properties(form.request_type_service_l3nm, _request_type_service_l3nm , disabled=status.running) set_properties(form.dlt_domain_id , status.parameters.dlt_domain_id , readonly=status.running)
set_properties(form.request_type_service_mw , _request_type_service_mw , disabled=status.running) set_properties(form.request_type_service_l2nm, _request_type_service_l2nm , disabled=status.running)
set_properties(form.request_type_service_tapi, _request_type_service_tapi , disabled=status.running) set_properties(form.request_type_service_l3nm, _request_type_service_l3nm , disabled=status.running)
set_properties(form.request_type_slice_l2nm , _request_type_slice_l2nm , disabled=status.running) set_properties(form.request_type_service_mw , _request_type_service_mw , disabled=status.running)
set_properties(form.request_type_slice_l3nm , _request_type_slice_l3nm , disabled=status.running) set_properties(form.request_type_service_tapi, _request_type_service_tapi , disabled=status.running)
set_properties(form.num_generated , status.num_generated , disabled=True) set_properties(form.request_type_slice_l2nm , _request_type_slice_l2nm , disabled=status.running)
set_properties(form.num_released , status.num_released , disabled=True) set_properties(form.request_type_slice_l3nm , _request_type_slice_l3nm , disabled=status.running)
set_properties(form.infinite_loop , status.infinite_loop , disabled=True) set_properties(form.num_generated , status.num_generated , disabled=True)
set_properties(form.running , status.running , 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.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') form_action = url_for('load_gen.stop') if status.running else url_for('load_gen.start')
...@@ -99,6 +101,8 @@ def start(): ...@@ -99,6 +101,8 @@ def start():
load_gen_params = Parameters() load_gen_params = Parameters()
load_gen_params.num_requests = form.num_requests.data 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.offered_load = form.offered_load.data
load_gen_params.holding_time = form.holding_time.data load_gen_params.holding_time = form.holding_time.data
load_gen_params.inter_arrival_time = form.inter_arrival_time.data load_gen_params.inter_arrival_time = form.inter_arrival_time.data
......
...@@ -83,6 +83,36 @@ ...@@ -83,6 +83,36 @@
</div> </div>
<br /> <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"> <div class="row mb-3">
{{ form.offered_load.label(class="col-sm-2 col-form-label") }} {{ form.offered_load.label(class="col-sm-2 col-form-label") }}
<div class="col-sm-10"> <div class="col-sm-10">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment