diff --git a/src/tests/tools/load_gen/Parameters.py b/src/tests/tools/load_gen/Parameters.py new file mode 100644 index 0000000000000000000000000000000000000000..f3fe742df51b4cb0d89d84a32a6b808949ce2479 --- /dev/null +++ b/src/tests/tools/load_gen/Parameters.py @@ -0,0 +1,48 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from typing import Optional + +class Parameters: + def __init__( + self, num_services : int, offered_load : Optional[float] = None, inter_arrival_time : Optional[float] = None, + holding_time : Optional[float] = None, dry_mode : bool = False + ) -> None: + self._num_services = num_services + self._offered_load = offered_load + self._inter_arrival_time = inter_arrival_time + self._holding_time = holding_time + self._dry_mode = dry_mode + + if self._offered_load is None and self._holding_time is not None and self._inter_arrival_time is not None: + self._offered_load = self._holding_time / self._inter_arrival_time + elif self._offered_load is not None and self._holding_time is not None and self._inter_arrival_time is None: + self._inter_arrival_time = self._holding_time / self._offered_load + elif self._offered_load is not None and self._holding_time is None and self._inter_arrival_time is not None: + self._holding_time = self._offered_load * self._inter_arrival_time + + @property + def num_services(self): return self._num_services + + @property + def offered_load(self): return self._offered_load + + @property + def inter_arrival_time(self): return self._inter_arrival_time + + @property + def holding_time(self): return self._holding_time + + @property + def dry_mode(self): return self._dry_mode diff --git a/src/tests/tools/load_gen/ServiceGenerator.py b/src/tests/tools/load_gen/ServiceGenerator.py new file mode 100644 index 0000000000000000000000000000000000000000..d21c345a315a8c3faff02647b80f3806a10b316c --- /dev/null +++ b/src/tests/tools/load_gen/ServiceGenerator.py @@ -0,0 +1,144 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, json, random, threading +from typing import Dict, Optional, Set, Tuple +from common.proto.context_pb2 import Empty +from common.tools.object_factory.Constraint import json_constraint_custom +from common.tools.object_factory.ConfigRule import json_config_rule_set +from common.tools.object_factory.Device import json_device_id +from common.tools.object_factory.EndPoint import json_endpoint_id +from common.tools.object_factory.Service import json_service_l2nm_planned +from context.client.ContextClient import ContextClient + +LOGGER = logging.getLogger(__name__) + +class ServiceGenerator: + def __init__(self) -> None: + self._lock = threading.Lock() + self._num_services = 0 + self._available_device_endpoints : Dict[str, Set[str]] = dict() + self._used_device_endpoints : Dict[str, Dict[str, str]] = dict() + + def initialize(self) -> None: + with self._lock: + self._available_device_endpoints.clear() + self._used_device_endpoints.clear() + + context_client = ContextClient() + + devices = context_client.ListDevices(Empty()) + for device in devices.devices: + device_uuid = device.device_id.device_uuid.uuid + _endpoints = self._available_device_endpoints.setdefault(device_uuid, set()) + for endpoint in device.device_endpoints: + endpoint_uuid = endpoint.endpoint_id.endpoint_uuid.uuid + _endpoints.add(endpoint_uuid) + + links = context_client.ListLinks(Empty()) + for link in links.links: + for endpoint_id in link.link_endpoint_ids: + device_uuid = endpoint_id.device_id.device_uuid.uuid + endpoint_uuid = endpoint_id.endpoint_uuid.uuid + _endpoints = self._available_device_endpoints.get(device_uuid, set()) + _endpoints.discard(endpoint_uuid) + if len(_endpoints) == 0: self._available_device_endpoints.pop(device_uuid, None) + + @property + def num_services_generated(self): return self._num_services + + def dump_state(self) -> None: + with self._lock: + _endpoints = { + device_uuid:[endpoint_uuid for endpoint_uuid in endpoint_uuids] + for device_uuid,endpoint_uuids in self._available_device_endpoints.items() + } + LOGGER.info('[dump_state] available_device_endpoints = {:s}'.format(json.dumps(_endpoints))) + LOGGER.info('[dump_state] used_device_endpoints = {:s}'.format(json.dumps(self._used_device_endpoints))) + + def _use_device_endpoint( + self, service_uuid : str, exclude_device_uuids : Set[str] = set() + ) -> Optional[Tuple[str, str]]: + with self._lock: + elegible_device_endpoints = { + device_uuid:device_endpoint_uuids + for device_uuid,device_endpoint_uuids in self._available_device_endpoints.items() + if device_uuid not in exclude_device_uuids and len(device_endpoint_uuids) > 0 + } + if len(elegible_device_endpoints) == 0: return None + device_uuid = random.choice(list(elegible_device_endpoints.keys())) + device_endpoint_uuids = elegible_device_endpoints.get(device_uuid) + endpoint_uuid = random.choice(list(device_endpoint_uuids)) + self._available_device_endpoints.setdefault(device_uuid, set()).discard(endpoint_uuid) + self._used_device_endpoints.setdefault(device_uuid, dict())[endpoint_uuid] = service_uuid + return device_uuid, endpoint_uuid + + def _release_device_endpoint(self, device_uuid : str, endpoint_uuid : str) -> None: + with self._lock: + self._used_device_endpoints.setdefault(device_uuid, set()).pop(endpoint_uuid, None) + self._available_device_endpoints.setdefault(device_uuid, set()).add(endpoint_uuid) + + def compose_service(self) -> Optional[Dict]: + with self._lock: + self._num_services += 1 + num_service = self._num_services + #service_uuid = str(uuid.uuid4()) + service_uuid = 'svc_{:d}'.format(num_service) + src = self._use_device_endpoint(service_uuid) + if src is None: return None + src_device_uuid,src_endpoint_uuid = src + dst = self._use_device_endpoint(service_uuid, exclude_device_uuids={src_device_uuid}) + if dst is None: + self._release_device_endpoint(src_device_uuid, src_endpoint_uuid) + return None + dst_device_uuid,dst_endpoint_uuid = dst + endpoint_ids = [ + json_endpoint_id(json_device_id(src_device_uuid), src_endpoint_uuid), + json_endpoint_id(json_device_id(dst_device_uuid), dst_endpoint_uuid), + ] + constraints = [ + json_constraint_custom('bandwidth[gbps]', '10.0'), + json_constraint_custom('latency[ms]', '20.0'), + ] + vlan_id = num_service % 1000 + circuit_id = '{:03d}'.format(vlan_id) + src_router_id = '.'.join([src_device_uuid.replace('R', ''), '0'] + src_endpoint_uuid.split('/')) + dst_router_id = '.'.join([dst_device_uuid.replace('R', ''), '0'] + dst_endpoint_uuid.split('/')) + config_rules = [ + json_config_rule_set('/settings', { + 'mtu': 1512 + }), + json_config_rule_set('/device[{:s}]/endpoint[{:s}]/settings'.format(src_device_uuid, src_endpoint_uuid), { + 'router_id': src_router_id, + 'sub_interface_index': vlan_id, + 'vlan_id': vlan_id, + 'remote_router': dst_router_id, + 'circuit_id': circuit_id, + }), + json_config_rule_set('/device[{:s}]/endpoint[{:s}]/settings'.format(dst_device_uuid, dst_endpoint_uuid), { + 'router_id': dst_router_id, + 'sub_interface_index': vlan_id, + 'vlan_id': vlan_id, + 'remote_router': src_router_id, + 'circuit_id': circuit_id, + }), + ] + return json_service_l2nm_planned( + service_uuid, endpoint_ids=endpoint_ids, constraints=constraints, config_rules=config_rules) + + def release_service(self, json_service : Dict) -> None: + for endpoint_id in json_service['service_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) diff --git a/src/tests/tools/load_gen/ServiceScheduler.py b/src/tests/tools/load_gen/ServiceScheduler.py new file mode 100644 index 0000000000000000000000000000000000000000..5a8b8dbdf02a7020186453b49f313c41ab850ef3 --- /dev/null +++ b/src/tests/tools/load_gen/ServiceScheduler.py @@ -0,0 +1,106 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import copy, logging, pytz, random +from datetime import datetime, timedelta +from apscheduler.executors.pool import ThreadPoolExecutor +from apscheduler.jobstores.memory import MemoryJobStore +from apscheduler.schedulers.blocking import BlockingScheduler +from typing import Dict +from common.proto.context_pb2 import Service, ServiceId +from service.client.ServiceClient import ServiceClient +from .Parameters import Parameters +from .ServiceGenerator import ServiceGenerator + +logging.getLogger('apscheduler.executors.default').setLevel(logging.WARNING) +logging.getLogger('apscheduler.scheduler').setLevel(logging.WARNING) + +LOGGER = logging.getLogger(__name__) + +class ServiceScheduler: + def __init__(self, parameters : Parameters, service_generator : ServiceGenerator) -> None: + self._scheduler = BlockingScheduler() + self._scheduler.configure( + jobstores = {'default': MemoryJobStore()}, + executors = {'default': ThreadPoolExecutor(max_workers=10)}, + job_defaults = { + 'coalesce': False, + 'max_instances': 100, + 'misfire_grace_time': 120, + }, + timezone=pytz.utc) + self._parameters = parameters + self._service_generator = service_generator + + def _schedule_service_setup(self) -> None: + if self._service_generator.num_services_generated >= self._parameters.num_services: + LOGGER.info('Generation Done!') + #self._scheduler.shutdown() + return + iat = random.expovariate(1.0 / self._parameters.inter_arrival_time) + run_date = datetime.utcnow() + timedelta(seconds=iat) + self._scheduler.add_job( + self._service_setup, trigger='date', run_date=run_date, timezone=pytz.utc) + + def _schedule_service_teardown(self, service : Dict) -> None: + ht = random.expovariate(1.0 / self._parameters.holding_time) + run_date = datetime.utcnow() + timedelta(seconds=ht) + self._scheduler.add_job( + self._service_teardown, args=(service,), trigger='date', run_date=run_date, timezone=pytz.utc) + + def start(self): + self._schedule_service_setup() + self._scheduler.start() + + def _service_setup(self) -> None: + self._schedule_service_setup() + + service = self._service_generator.compose_service() + if service is None: + LOGGER.warning('No resources available to compose new service') + return + + service_uuid = service['service_id']['service_uuid']['uuid'] + src_device_uuid = service['service_endpoint_ids'][0]['device_id']['device_uuid']['uuid'] + src_endpoint_uuid = service['service_endpoint_ids'][0]['endpoint_uuid']['uuid'] + dst_device_uuid = service['service_endpoint_ids'][1]['device_id']['device_uuid']['uuid'] + dst_endpoint_uuid = service['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) + + if not self._parameters.dry_mode: + service_add = copy.deepcopy(service) + service_add['service_endpoint_ids'] = [] + service_add['service_constraints'] = [] + service_add['service_config'] = {'config_rules': []} + service_client = ServiceClient() # create instances per request to load balance between pods + service_client.CreateService(Service(**service_add)) + service_client.UpdateService(Service(**service)) + + self._schedule_service_teardown(service) + + def _service_teardown(self, service : Dict) -> None: + service_uuid = service['service_id']['service_uuid']['uuid'] + src_device_uuid = service['service_endpoint_ids'][0]['device_id']['device_uuid']['uuid'] + src_endpoint_uuid = service['service_endpoint_ids'][0]['endpoint_uuid']['uuid'] + dst_device_uuid = service['service_endpoint_ids'][1]['device_id']['device_uuid']['uuid'] + dst_endpoint_uuid = service['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) + + if not self._parameters.dry_mode: + service_client = ServiceClient() # create instances per request to load balance between pods + service_client.DeleteService(ServiceId(**(service['service_id']))) + + self._service_generator.release_service(service) diff --git a/src/tests/tools/load_gen/__init__.py b/src/tests/tools/load_gen/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..70a33251242c51f49140e596b8208a19dd5245f7 --- /dev/null +++ b/src/tests/tools/load_gen/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/src/tests/tools/load_gen/__main__.py b/src/tests/tools/load_gen/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..7a81dbcba7cd42b703ecb078751db6d0fa705750 --- /dev/null +++ b/src/tests/tools/load_gen/__main__.py @@ -0,0 +1,44 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging, sys +from .Parameters import Parameters +from .ServiceGenerator import ServiceGenerator +from .ServiceScheduler import ServiceScheduler + +logging.basicConfig(level=logging.INFO) +LOGGER = logging.getLogger(__name__) + +def main(): + LOGGER.info('Starting...') + parameters = Parameters( + num_services = 100, + offered_load = 50, + holding_time = 10, + dry_mode = False, # in dry mode, no request is sent to TeraFlowSDN + ) + + LOGGER.info('Initializing Generator...') + service_generator = ServiceGenerator() + service_generator.initialize() + + LOGGER.info('Running Schedule...') + scheduler = ServiceScheduler(parameters, service_generator) + scheduler.start() + + LOGGER.info('Done!') + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/tests/tools/load_gen/deploy_specs.sh b/src/tests/tools/load_gen/deploy_specs.sh new file mode 100644 index 0000000000000000000000000000000000000000..238918480ae857e64efb52f652b20ab08a21c2df --- /dev/null +++ b/src/tests/tools/load_gen/deploy_specs.sh @@ -0,0 +1,26 @@ +# Set the URL of your local Docker registry where the images will be uploaded to. +export TFS_REGISTRY_IMAGE="http://localhost:32000/tfs/" + +# Set the list of components, separated by spaces, you want to build images for, and deploy. +# Supported components are: +# context device automation policy service compute monitoring webui +# interdomain slice pathcomp dlt +# dbscanserving opticalattackmitigator opticalattackdetector +# l3_attackmitigator l3_centralizedattackdetector l3_distributedattackdetector +export TFS_COMPONENTS="context device pathcomp service slice webui" # automation monitoring compute + +# Set the tag you want to use for your images. +export TFS_IMAGE_TAG="dev" + +# Set the name of the Kubernetes namespace to deploy to. +export TFS_K8S_NAMESPACE="tfs" + +# Set additional manifest files to be applied after the deployment +export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml manifests/servicemonitors.yaml" + +# Set the new Grafana admin password +export TFS_GRAFANA_PASSWORD="admin123+" + +# If not already set, disable skip-build flag. +# If TFS_SKIP_BUILD is "YES", the containers are not rebuilt-retagged-repushed and existing ones are used. +export TFS_SKIP_BUILD="NO" #${TFS_SKIP_BUILD:-"YES"} diff --git a/src/tests/tools/load_gen/descriptors.json b/src/tests/tools/load_gen/descriptors.json new file mode 100644 index 0000000000000000000000000000000000000000..5fb0c086749cab3343277c28a902b3db48651320 --- /dev/null +++ b/src/tests/tools/load_gen/descriptors.json @@ -0,0 +1,229 @@ +{ + "contexts": [ + { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "topology_ids": [], "service_ids": [] + } + ], + "topologies": [ + { + "topology_id": { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "topology_uuid": {"uuid": "admin"} + }, + "device_ids": [ + {"device_uuid": {"uuid": "R1"}}, + {"device_uuid": {"uuid": "R2"}}, + {"device_uuid": {"uuid": "R3"}}, + {"device_uuid": {"uuid": "R4"}}, + {"device_uuid": {"uuid": "R5"}}, + {"device_uuid": {"uuid": "R6"}}, + {"device_uuid": {"uuid": "R7"}} + ], + "link_ids": [ + {"link_uuid": {"uuid": "R1==R2"}}, + {"link_uuid": {"uuid": "R2==R3"}}, + {"link_uuid": {"uuid": "R3==R4"}}, + {"link_uuid": {"uuid": "R4==R5"}}, + {"link_uuid": {"uuid": "R5==R6"}}, + {"link_uuid": {"uuid": "R6==R1"}}, + {"link_uuid": {"uuid": "R1==R7"}}, + {"link_uuid": {"uuid": "R3==R7"}}, + {"link_uuid": {"uuid": "R5==R7"}} + ] + } + ], + "devices": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R4"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R5"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R6"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "1/4"}, + {"sample_types": [], "type": "copper", "uuid": "1/5"}, + {"sample_types": [], "type": "copper", "uuid": "1/6"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"} + ]}}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R7"}}, "device_type": "emu-packet-router", "device_drivers": [0], + "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}}, + {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}}, + {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [ + {"sample_types": [], "type": "copper", "uuid": "1/1"}, + {"sample_types": [], "type": "copper", "uuid": "1/2"}, + {"sample_types": [], "type": "copper", "uuid": "1/3"}, + {"sample_types": [], "type": "copper", "uuid": "2/1"}, + {"sample_types": [], "type": "copper", "uuid": "2/2"}, + {"sample_types": [], "type": "copper", "uuid": "2/3"}, + {"sample_types": [], "type": "copper", "uuid": "2/4"}, + {"sample_types": [], "type": "copper", "uuid": "2/5"}, + {"sample_types": [], "type": "copper", "uuid": "2/6"} + ]}}} + ]} + } + ], + "links": [ + { + "link_id": {"link_uuid": {"uuid": "R1==R2"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R2==R3"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R3==R4"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R4==R5"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R4"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R5==R6"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R6==R1"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R6"}}, "endpoint_uuid": {"uuid": "2/1"}}, + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/2"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R1==R7"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "2/3"}}, + {"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/1"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R3==R7"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "2/3"}}, + {"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/3"}} + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R5==R7"}}, + "link_endpoint_ids": [ + {"device_id": {"device_uuid": {"uuid": "R5"}}, "endpoint_uuid": {"uuid": "2/3"}}, + {"device_id": {"device_uuid": {"uuid": "R7"}}, "endpoint_uuid": {"uuid": "2/5"}} + ] + } + ] +} \ No newline at end of file diff --git a/src/tests/tools/load_gen/run.sh b/src/tests/tools/load_gen/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..b16808ab6905927728212185681e2a6d4a5135ba --- /dev/null +++ b/src/tests/tools/load_gen/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source tfs_runtime_env_vars.sh +python -m tests.tools.load_gen