From abe5ed2fb167bd7cec18c20bca90565c3196b08b Mon Sep 17 00:00:00 2001 From: nanitebased Date: Fri, 7 Jul 2023 10:38:14 +0200 Subject: [PATCH 01/14] Add prefix to all API endpoints --- Scheduler/__init__.py | 8 ++++---- docs/A1_ENDPOINTS.md | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Scheduler/__init__.py b/Scheduler/__init__.py index 129c0eb..659797c 100644 --- a/Scheduler/__init__.py +++ b/Scheduler/__init__.py @@ -37,18 +37,18 @@ def _showValidation(name, validation): HeartBeat.Initialize() from Scheduler.execution import bp as ExecutionBp -app.register_blueprint(ExecutionBp, url_prefix='/execution') +app.register_blueprint(ExecutionBp, url_prefix='/elcm/api/v1/execution') from Scheduler.dispatcher import bp as DispatcherBp app.register_blueprint(DispatcherBp, url_prefix='/api/v0', name='deprecatedDispatcherApi') -app.register_blueprint(DispatcherBp, url_prefix='/experiment') +app.register_blueprint(DispatcherBp, url_prefix='/elcm/api/v1/experiment') from Scheduler.facility import bp as FacilityBp -app.register_blueprint(FacilityBp, url_prefix='/facility') +app.register_blueprint(FacilityBp, url_prefix='/elcm/api/v1/facility') if config.EastWest.Enabled: from Scheduler.east_west import bp as EastwestBp - app.register_blueprint(EastwestBp, url_prefix='/distributed') + app.register_blueprint(EastwestBp, url_prefix='/elcm/api/v1/distributed') Log.I(f'Optional East/West interface is {Log.State(config.EastWest.Enabled)}') diff --git a/docs/A1_ENDPOINTS.md b/docs/A1_ENDPOINTS.md index 3563e63..f1abfe5 100644 --- a/docs/A1_ENDPOINTS.md +++ b/docs/A1_ENDPOINTS.md @@ -1,11 +1,11 @@ # REST Endpoints > ⚠ The endpoints of the ELCM are not expected to be exposed to the Internet and may leak information. For user -> management and authorization always use a different front-end, such as the Dispatcher. +> management and authorization always use a different front-end, such as the Dispatcher. ## Experiment management endpoints -### [POST] `/experiment/run` +### [POST] `/elcm/api/v1/experiment/run` > *[POST] `/api/v0/run` (Deprecated)* Creates and queues a new experiment execution, based on the contents of the received Experiment Descriptor (JSON). @@ -15,8 +15,8 @@ Replies with the following response JSON: ``` Where is a unique execution identification that can be used as input in other endpoints. -### [GET] `/execution//status` -> *[GET] `/execution//json` (Deprecated)* +### [GET] `/elcm/api/v1/execution//status` +> *[GET] `/elcm/api/v1/execution//json` (Deprecated)* Returns a JSON that contains general information about the status of the selected execution id, with the following format: @@ -28,7 +28,7 @@ format: “Verdict”: } ``` -### [GET] `/execution//logs` +### [GET] `/elcm/api/v1/execution//logs` Returns a JSON that contains all the log messages generated by the execution, separated by stage: ```text @@ -38,15 +38,15 @@ Returns a JSON that contains all the log messages generated by the execution, se “PostRun”: } ``` -### [GET] `/execution//results` +### [GET] `/elcm/api/v1/execution//results` Returns a compressed file that includes the logs and all files generated by the experiment execution. -### [GET] `/execution//descriptor` +### [GET] `/elcm/api/v1/execution//descriptor` Returns a copy of the Experiment Descriptor that was used to define the execution. -### [GET] '/execution//kpis' +### [GET] `/elcm/api/v1/execution//kpis` Returns a dictionary with a single `KPIs` key, containing a list of pairs (`measurement`, `kpi`) that are considered of interest. @@ -54,21 +54,21 @@ interest. > These values can be used as part of queries to the [Analytics Module](https://github.com/5genesis/Analytics), in order > to extract a sub-set of important KPIs from all the generated measurements. -### [DELETE] `/execution/` -> *[GET] `/execution//cancel` (Deprecated)* +### [DELETE] `/elcm/api/v1/execution/` +> *[GET] `/elcm/api/v1/execution//cancel` (Deprecated)* Marks the selected execution for cancellation. The execution will be cancelled after finalization of the current task. ## Facility information -### [GET] `/facility/baseSliceDescriptors` +### [GET] `/elcm/api/v1/facility/baseSliceDescriptors` Returns a list of available Base Slice Descriptors, with the following format: ```json { "SliceDescriptors": [] } ``` -### [GET] `/facility/testcases` +### [GET] `/elcm/api/v1/facility/testcases` Returns a list of available UEs, with the following format: ```text @@ -86,14 +86,14 @@ Returns a list of available UEs, with the following format: } ``` -### [GET] `/facility/ues` +### [GET] `/elcm/api/v1/facility/ues` Returns a list of available UEs, with the following format: ```json { "UEs": [] } ``` -### [GET] `/facility/resource_status` +### [GET] `/elcm/api/v1/facility/resource_status` Returns a list of available Resources, separated by current usage status: ```json @@ -101,7 +101,7 @@ Returns a list of available Resources, separated by current usage status: "Idle": [] } ``` -### [GET] `/facility/scenarios` +### [GET] `/elcm/api/v1/facility/scenarios` Returns a list of available Scenarios, with the following format: ```json From 7f6ae97f74671b596d573d3b977702de2dce5a15 Mon Sep 17 00:00:00 2001 From: nanitebased Date: Fri, 15 Sep 2023 12:15:51 +0200 Subject: [PATCH 02/14] Add optional description, type to KPI definitions --- Facility/Loader/testcase_loader.py | 20 ++++++++++++++++---- Facility/facility.py | 4 ++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Facility/Loader/testcase_loader.py b/Facility/Loader/testcase_loader.py index b65e16c..20d723d 100644 --- a/Facility/Loader/testcase_loader.py +++ b/Facility/Loader/testcase_loader.py @@ -25,7 +25,7 @@ class TestCaseLoader(Loader): testCases: Dict[str, List[ActionInformation]] = {} extra: Dict[str, Dict[str, object]] = {} dashboards: Dict[str, List[DashboardPanel]] = {} - kpis: Dict[str, List[Tuple[str, str]]] = {} + kpis: Dict[str, List[Tuple[str, str, str, str]]] = {} # (Measurement, KPI, Type, Description) parameters: Dict[str, Tuple[str, str]] = {} # For use only while processing data, not necessary afterwards @classmethod @@ -100,10 +100,22 @@ def validateKPIs(cls, key: str, defs: TestCaseData) -> [(Level, str)]: (Level.ERROR, f"KPIs for '{measurement}' ({key}) are not a list. Found '{kpiList}'")) elif len(kpiList) == 0: validation.append( - (Level.ERROR, f"'{measurement}' ({key}) defines an empty listf of KPIs")) + (Level.ERROR, f"'{measurement}' ({key}) defines an empty list of KPIs")) else: - for kpi in sorted(kpiList): - kpis.append((measurement, kpi)) + for kpi in sorted(kpiList, key=lambda x: x if isinstance(x, str) else x.get('Name', '')): + description = kind = "" + if isinstance(kpi, str): + name = kpi + elif isinstance(kpi, dict): + name = kpi.get('Name', '') + description = kpi.get('Description', '') + kind = kpi.get('Type', '') + else: + validation.append( + (Level.ERROR, f"KPI definitions for '{measurement}' must either be str or a " + f"dictionary (keys ['Name', 'Type', 'Description']). Found '{kpi}'")) + continue + kpis.append((measurement, name, kind, description)) except Exception as e: validation.append((Level.ERROR, f"Could not read KPIs dictionary for testcase '{key}': {e}")) diff --git a/Facility/facility.py b/Facility/facility.py index 72df8a4..07d5d23 100644 --- a/Facility/facility.py +++ b/Facility/facility.py @@ -24,7 +24,7 @@ class Facility: testCases: Dict[str, List[ActionInformation]] = {} extra: Dict[str, Dict[str, object]] = {} dashboards: Dict[str, List[DashboardPanel]] = {} - kpis: Dict[str, List[Tuple[str, str]]] = {} + kpis: Dict[str, List[Tuple[str, str, str, str]]] = {} resources: Dict[str, Resource] = {} scenarios: Dict[str, Dict] = {} @@ -98,7 +98,7 @@ def GetTestCaseExtra(cls, id: str) -> Dict[str, object]: return cls.extra.get(id, {}) @classmethod - def GetTestCaseKPIs(cls, id: str) -> List[Tuple[str, str]]: + def GetTestCaseKPIs(cls, id: str) -> List[Tuple[str, str, str, str]]: return cls.kpis.get(id, []) @classmethod From c6682d16e7f907e9e34013a403c607f52823490f Mon Sep 17 00:00:00 2001 From: nanitebased Date: Fri, 15 Sep 2023 12:17:24 +0200 Subject: [PATCH 03/14] Return objects instead of tuples in /kpis route --- Scheduler/execution/routes.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Scheduler/execution/routes.py b/Scheduler/execution/routes.py index 82b4f27..e09ad39 100644 --- a/Scheduler/execution/routes.py +++ b/Scheduler/execution/routes.py @@ -138,7 +138,14 @@ def kpis(executionId: int): for testcase in descriptor.TestCases: kpis.update(Facility.GetTestCaseKPIs(testcase)) - return jsonify({"KPIs": sorted(kpis)}) + res = [] + for kpi in sorted(kpis): + measurement, name, kind, description = kpi + res.append({ + 'Measurement': measurement, 'KPI': name, 'Type': kind, 'Description': description + }) + + return jsonify({"KPIs": res}) else: return f"Execution {executionId} not found", 404 From 91dbaf86c7bc230c1552e98da9e5b7213b87f1f5 Mon Sep 17 00:00:00 2001 From: nanitebased Date: Fri, 15 Sep 2023 12:26:23 +0200 Subject: [PATCH 04/14] Update documentation --- CHANGELOG.md | 4 ++++ docs/A1_ENDPOINTS.md | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58cad6a..830e512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +**15/09/2023** [Version 3.6.2] + - Add a prefix (`/elcm/api/v1/`) to all endpoints + - Allow defining and return a more complete description of the KPIs in the `/elcm/api/v1//kpis` endpoint + **09/11/2022** [Version 3.6.1] - Allow defining a set of KPIs per TestCase - Implement `/execution//kpis` endpoint diff --git a/docs/A1_ENDPOINTS.md b/docs/A1_ENDPOINTS.md index f1abfe5..bcd6582 100644 --- a/docs/A1_ENDPOINTS.md +++ b/docs/A1_ENDPOINTS.md @@ -48,8 +48,17 @@ Returns a copy of the Experiment Descriptor that was used to define the executio ### [GET] `/elcm/api/v1/execution//kpis` -Returns a dictionary with a single `KPIs` key, containing a list of pairs (`measurement`, `kpi`) that are considered of -interest. +Returns a dictionary with a single `KPIs` key, containing a list of objects that describe KPIs that are considered of +interest. The objects have the following format: + +```text +{ + "Measurement": , + "KPI": , + "Type": , + "Description": +} +``` > These values can be used as part of queries to the [Analytics Module](https://github.com/5genesis/Analytics), in order > to extract a sub-set of important KPIs from all the generated measurements. From 5414dc304237cdea76a7deeba00dc450187681dd Mon Sep 17 00:00:00 2001 From: nanitebased Date: Thu, 21 Sep 2023 11:27:38 +0200 Subject: [PATCH 05/14] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 830e512..c6a0ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -**15/09/2023** [Version 3.6.2] +**21/09/2023** [Version 3.6.2] - Add a prefix (`/elcm/api/v1/`) to all endpoints - Allow defining and return a more complete description of the KPIs in the `/elcm/api/v1//kpis` endpoint From f8c591aad2a0b614bde0044131073ad44eb6c98e Mon Sep 17 00:00:00 2001 From: nanitebased Date: Thu, 28 Sep 2023 09:13:29 +0200 Subject: [PATCH 06/14] Enable original endpoints --- CHANGELOG.md | 3 +++ Scheduler/__init__.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a0ba7..57bad49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +**28/09/2023** [Version 3.6.3] + - Re-enable original endpoints (deprecated) to retain compatibility with Portal + **21/09/2023** [Version 3.6.2] - Add a prefix (`/elcm/api/v1/`) to all endpoints - Allow defining and return a more complete description of the KPIs in the `/elcm/api/v1//kpis` endpoint diff --git a/Scheduler/__init__.py b/Scheduler/__init__.py index 659797c..08fb7d4 100644 --- a/Scheduler/__init__.py +++ b/Scheduler/__init__.py @@ -37,6 +37,7 @@ def _showValidation(name, validation): HeartBeat.Initialize() from Scheduler.execution import bp as ExecutionBp +app.register_blueprint(ExecutionBp, url_prefix='/execution', name='deprecatedExecutionApi') app.register_blueprint(ExecutionBp, url_prefix='/elcm/api/v1/execution') from Scheduler.dispatcher import bp as DispatcherBp @@ -44,10 +45,12 @@ def _showValidation(name, validation): app.register_blueprint(DispatcherBp, url_prefix='/elcm/api/v1/experiment') from Scheduler.facility import bp as FacilityBp +app.register_blueprint(FacilityBp, url_prefix='/facility', name='deprecatedFacilityApi') app.register_blueprint(FacilityBp, url_prefix='/elcm/api/v1/facility') if config.EastWest.Enabled: from Scheduler.east_west import bp as EastwestBp + app.register_blueprint(EastwestBp, url_prefix='/distributed', name='deprecatedEastWestApi') app.register_blueprint(EastwestBp, url_prefix='/elcm/api/v1/distributed') Log.I(f'Optional East/West interface is {Log.State(config.EastWest.Enabled)}') From b39256db0a6a7adcaff704aecb6d9bec26619008 Mon Sep 17 00:00:00 2001 From: nanitebased Date: Wed, 4 Oct 2023 15:20:36 +0200 Subject: [PATCH 07/14] Pin requirements to tested versions Avoid deploying using Flask>=3.0.0 (untested, causes exceptions) --- requirements.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/requirements.txt b/requirements.txt index a3988fa..da1e413 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -Flask>=1.0.2 -Flask-Bootstrap>=3.3.7.1 -Flask-Moment>=0.6.0 -flask-paginate>=0.5.2 -influxdb>=5.2.2 -psutil>=5.6.1 -python-dotenv>=0.10.1 -PyYAML>=3.12 +Flask~=2.3.0 +Flask-Bootstrap~=3.3.7.1 +Flask-Moment~=1.0.5 +flask-paginate~=2022.1.8 +influxdb~=5.3.1 +psutil~=5.9.5 +python-dotenv~=1.0.0 +PyYAML~=6.0 From 2d7235443dfeaf32f3399bd545983e74cb12a535 Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Fri, 23 Feb 2024 08:53:08 +0100 Subject: [PATCH 08/14] Implemented app eviction and fixed post run after cancel. --- Experiment/EvictedScripts/app-evition.ps1 | 8 ++++++++ Experiment/experiment_run.py | 18 ++++++++++++++++++ Interfaces/management.py | 7 ++++--- Scheduler/execution/routes.py | 2 +- start.sh | 2 +- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 Experiment/EvictedScripts/app-evition.ps1 diff --git a/Experiment/EvictedScripts/app-evition.ps1 b/Experiment/EvictedScripts/app-evition.ps1 new file mode 100644 index 0000000..ba41fec --- /dev/null +++ b/Experiment/EvictedScripts/app-evition.ps1 @@ -0,0 +1,8 @@ +$packageOutput = $(adb -s $args[0] shell pm list packages) + +$packageOutput | ForEach-Object { + $package = $_ -replace '^package' + if ($package -match 'com.uma.(.+)'){ + adb -s $args[0] shell am force-stop $matches[0] + } +} \ No newline at end of file diff --git a/Experiment/experiment_run.py b/Experiment/experiment_run.py index 1535254..2b1dd4b 100644 --- a/Experiment/experiment_run.py +++ b/Experiment/experiment_run.py @@ -9,6 +9,7 @@ from Interfaces import PortalApi from Composer import Composer, PlatformConfiguration from os.path import join, abspath +from Helper import Cli @unique @@ -16,6 +17,19 @@ class CoarseStatus(Enum): Init, PreRun, Run, PostRun, Finished, Cancelled, Errored = range(7) +class AppEviction: + def __init__(self, device_id: str): + self.deviceId = device_id + + @classmethod + def run(self): + pass + + @classmethod + def os_detection(self): + pass + + class ExperimentRun: portal: PortalApi = None grafana = None @@ -147,6 +161,10 @@ def Cancel(self): if current is not None: current.RequestStop() self.CoarseStatus = CoarseStatus.Cancelled + ###### + # Make the app evicted with adb .... + ###### + self.PostRunner.Start() # Temporal fix for the release of the resources after the cancellation. def PreRun(self): self.CoarseStatus = CoarseStatus.PreRun diff --git a/Interfaces/management.py b/Interfaces/management.py index be293c6..95ce3dd 100644 --- a/Interfaces/management.py +++ b/Interfaces/management.py @@ -6,6 +6,7 @@ from Facility import Facility + class Management: sliceManager = None @@ -16,7 +17,7 @@ def HasResources(cls, owner: 'ExecutorBase', localResources: List[str], - Available indicates that the required local resources are locked and can be used, and there are enough on all VIMs to fit the network services. - A feasible value of False indicates that the network services can never fit on the VIMs due to - their total resoutces. + their total resources. """ if len(networkServices) != 0: @@ -47,7 +48,6 @@ def HasResources(cls, owner: 'ExecutorBase', localResources: List[str], return False, True # Execution possible, but not enough resources at the moment return Facility.TryLockResources(localResources, owner, exclusive), True - @classmethod def ReleaseLocalResources(cls, owner: 'ExecutorBase', localResources: List[str]): Facility.ReleaseResources(localResources, owner) @@ -144,7 +144,8 @@ def GetNsdData(self, nsd: str) -> Tuple[Optional[str], Optional[str], Optional[M if isinstance(data, list): if len(data) != 0: data = data[0] - else: raise RuntimeError("Received an empty list") + else: + raise RuntimeError("Received an empty list") try: flavor = data["flavor"] return data['nsd-name'], data['nsd-id'], Metal(cpu=flavor["vcpu-count"], diff --git a/Scheduler/execution/routes.py b/Scheduler/execution/routes.py index e09ad39..014b5da 100644 --- a/Scheduler/execution/routes.py +++ b/Scheduler/execution/routes.py @@ -10,7 +10,7 @@ @bp.route('/cancel') # Deprecated -@bp.route('', methods=["DELETE"]) +# @bp.route('', methods=["DELETE"]) def cancel(executionId: int): ExecutionQueue.Cancel(executionId) flash(f'Cancelled execution {executionId}', 'info') diff --git a/start.sh b/start.sh index 791057d..f72596e 100644 --- a/start.sh +++ b/start.sh @@ -8,6 +8,6 @@ fi echo Starting ELCM on port $port source ./venv/bin/activate -export SECRET_KEY='' +export SECRET_KEY='super secret' flask run --host 0.0.0.0 --port $port deactivate From 1bba8d4663b692c11e86d714c50bace53f217750 Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Mon, 26 Feb 2024 15:28:04 +0100 Subject: [PATCH 09/14] Implemented stop-app with python instead of scripts. --- Experiment/EvictedScripts/app-evition.ps1 | 8 ----- Experiment/experiment_run.py | 37 +++++++++++++---------- 2 files changed, 21 insertions(+), 24 deletions(-) delete mode 100644 Experiment/EvictedScripts/app-evition.ps1 diff --git a/Experiment/EvictedScripts/app-evition.ps1 b/Experiment/EvictedScripts/app-evition.ps1 deleted file mode 100644 index ba41fec..0000000 --- a/Experiment/EvictedScripts/app-evition.ps1 +++ /dev/null @@ -1,8 +0,0 @@ -$packageOutput = $(adb -s $args[0] shell pm list packages) - -$packageOutput | ForEach-Object { - $package = $_ -replace '^package' - if ($package -match 'com.uma.(.+)'){ - adb -s $args[0] shell am force-stop $matches[0] - } -} \ No newline at end of file diff --git a/Experiment/experiment_run.py b/Experiment/experiment_run.py index 2b1dd4b..f6ef9ae 100644 --- a/Experiment/experiment_run.py +++ b/Experiment/experiment_run.py @@ -1,3 +1,6 @@ +import subprocess +import re + from Executor import PreRunner, Executor, PostRunner, ExecutorBase, Verdict from Data import ExperimentDescriptor from typing import Dict, Optional, List @@ -17,19 +20,6 @@ class CoarseStatus(Enum): Init, PreRun, Run, PostRun, Finished, Cancelled, Errored = range(7) -class AppEviction: - def __init__(self, device_id: str): - self.deviceId = device_id - - @classmethod - def run(self): - pass - - @classmethod - def os_detection(self): - pass - - class ExperimentRun: portal: PortalApi = None grafana = None @@ -161,9 +151,7 @@ def Cancel(self): if current is not None: current.RequestStop() self.CoarseStatus = CoarseStatus.Cancelled - ###### - # Make the app evicted with adb .... - ###### + self.AppEviction() self.PostRunner.Start() # Temporal fix for the release of the resources after the cancellation. def PreRun(self): @@ -285,3 +273,20 @@ def Save(self): @classmethod def Digest(cls, id: str) -> Dict: return Serialize.Load(Serialize.Path('Execution', id)) + + def AppEviction(self): + list_command = f'adb -s {self.Params["DeviceID"]} shell pm list packages' + pattern = r"(.*)(com.uma.(.*))" + process = subprocess.Popen(list_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') + pipe = process.stdout + + for line in iter(pipe.readline, b''): + try: + result = re.search(pattern, line.decode('utf-8')) + if result: + stop_command = f'adb -s {self.Params["DeviceID"]} shell am force-stop {result.group(2)}' + subprocess.Popen(stop_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') + Log.I(f"Package {result.group(2)} stopped.") + + except Exception as e: + Log.E(f"DECODING EXCEPTION: {e}") From dd5fac6f382e504cb6f938c01bffd830c4c7beb2 Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Fri, 1 Mar 2024 09:08:34 +0100 Subject: [PATCH 10/14] Closing tap instances when cancel experiment. --- Experiment/experiment_run.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/Experiment/experiment_run.py b/Experiment/experiment_run.py index f6ef9ae..eac49b9 100644 --- a/Experiment/experiment_run.py +++ b/Experiment/experiment_run.py @@ -1,5 +1,6 @@ import subprocess import re +import platform from Executor import PreRunner, Executor, PostRunner, ExecutorBase, Verdict from Data import ExperimentDescriptor @@ -151,7 +152,9 @@ def Cancel(self): if current is not None: current.RequestStop() self.CoarseStatus = CoarseStatus.Cancelled - self.AppEviction() + for device_id in self.Params["DeviceId"]: + self.AppEviction(device_id) + self.TapEviction() self.PostRunner.Start() # Temporal fix for the release of the resources after the cancellation. def PreRun(self): @@ -274,19 +277,33 @@ def Save(self): def Digest(cls, id: str) -> Dict: return Serialize.Load(Serialize.Path('Execution', id)) - def AppEviction(self): - list_command = f'adb -s {self.Params["DeviceID"]} shell pm list packages' + def AppEviction(self, device_id): + commands = f'adb -s {device_id} shell pm list packages' pattern = r"(.*)(com.uma.(.*))" - process = subprocess.Popen(list_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') + process = subprocess.Popen(commands.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') pipe = process.stdout for line in iter(pipe.readline, b''): try: result = re.search(pattern, line.decode('utf-8')) if result: - stop_command = f'adb -s {self.Params["DeviceID"]} shell am force-stop {result.group(2)}' - subprocess.Popen(stop_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') + app_stop_command = f'adb -s {device_id} shell am force-stop {result.group(2)}' + subprocess.Popen(app_stop_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') Log.I(f"Package {result.group(2)} stopped.") - except Exception as e: Log.E(f"DECODING EXCEPTION: {e}") + + def TapEviction(self): + if platform.system() == 'Linux': + pass + elif platform.system() == 'Windows': + commands = '$(Get-Process | Where-Object { $_.ProcessName -eq "tap" }).Id' + process = subprocess.Popen(commands.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=".") + pipe = process.stdout + + for line in iter(pipe.readline, b''): + try: + tap_stop_command = f"kill {line.decode('utf-8')}" + subprocess.Popen(tap_stop_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=".") + except Exception as e: + Log.W(f"{e}. Cannot find a process with the process identifier {line.decode('utf-8')}.") From eb15902905aedf16f868ac96fea2781c709a074f Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Thu, 25 Apr 2024 14:53:21 +0200 Subject: [PATCH 11/14] Fixed function for process eviction --- Experiment/experiment_run.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Experiment/experiment_run.py b/Experiment/experiment_run.py index eac49b9..748b7b3 100644 --- a/Experiment/experiment_run.py +++ b/Experiment/experiment_run.py @@ -152,8 +152,7 @@ def Cancel(self): if current is not None: current.RequestStop() self.CoarseStatus = CoarseStatus.Cancelled - for device_id in self.Params["DeviceId"]: - self.AppEviction(device_id) + self.AppEviction(self.Params["DeviceId"]) self.TapEviction() self.PostRunner.Start() # Temporal fix for the release of the resources after the cancellation. @@ -297,13 +296,5 @@ def TapEviction(self): if platform.system() == 'Linux': pass elif platform.system() == 'Windows': - commands = '$(Get-Process | Where-Object { $_.ProcessName -eq "tap" }).Id' - process = subprocess.Popen(commands.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=".") - pipe = process.stdout - - for line in iter(pipe.readline, b''): - try: - tap_stop_command = f"kill {line.decode('utf-8')}" - subprocess.Popen(tap_stop_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=".") - except Exception as e: - Log.W(f"{e}. Cannot find a process with the process identifier {line.decode('utf-8')}.") + tap_stop_command = f'taskkill /IM "tap.exe" /F' + subprocess.run(tap_stop_command, shell=True) From cd66fb388b8b2ba05db29ee181b7131888c5e94c Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Mon, 29 Apr 2024 13:42:34 +0200 Subject: [PATCH 12/14] Fixed parameter lists in Cli task. --- Helper/cli_executor.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Helper/cli_executor.py b/Helper/cli_executor.py index ea807b3..1b8f0ce 100644 --- a/Helper/cli_executor.py +++ b/Helper/cli_executor.py @@ -5,7 +5,9 @@ class Cli: def __init__(self, parameters: List[str], cwd: str, logger: Callable): - self.parameters = parameters + + aux_list = list(map(str.split, parameters)) + self.parameters = [elem for sublist in aux_list for elem in sublist] self.cwd = cwd self.logger = logger @@ -19,7 +21,9 @@ def stdout(self, process: subprocess.Popen): pipe = process.stdout for line in iter(pipe.readline, b''): - try: line = line.decode('utf-8').rstrip() - except Exception as e: line = f"DECODING EXCEPTION: {e}" + try: + line = line.decode('utf-8').rstrip() + except Exception as e: + line = f"DECODING EXCEPTION: {e}" self.logger(Level.INFO, f"[CLI]{line}") From c8134541f5c3dda0fd7f5341a16edce330b9d60c Mon Sep 17 00:00:00 2001 From: jj Date: Wed, 1 May 2024 00:01:45 +0200 Subject: [PATCH 13/14] Fixed format for parameters in cli executor. run_script.py in progress --- Executor/Tasks/Run/run_script.py | 20 ++++++++++++++++++++ Experiment/experiment_run.py | 6 ++++-- Helper/cli_executor.py | 7 +++---- 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 Executor/Tasks/Run/run_script.py diff --git a/Executor/Tasks/Run/run_script.py b/Executor/Tasks/Run/run_script.py new file mode 100644 index 0000000..da71b65 --- /dev/null +++ b/Executor/Tasks/Run/run_script.py @@ -0,0 +1,20 @@ +from Task import Task +from Helper import Cli +import platform + + +class RunScript(Task): + def __init__(self, logMethod, parent, params): + super().__init__("CLI Execute", parent, params, logMethod, None) + self.paramRules = { + 'Parameters': (None, True), + 'CWD': (None, True) + } + + def Run(self): + parameters = self.params['Parameters'] + if platform.system() == 'Windows': + pass + + cli = Cli(parameters, self.params['CWD'], self.Log) + cli.Execute() diff --git a/Experiment/experiment_run.py b/Experiment/experiment_run.py index 748b7b3..8c9b6be 100644 --- a/Experiment/experiment_run.py +++ b/Experiment/experiment_run.py @@ -276,7 +276,8 @@ def Save(self): def Digest(cls, id: str) -> Dict: return Serialize.Load(Serialize.Path('Execution', id)) - def AppEviction(self, device_id): + @staticmethod + def AppEviction(device_id): commands = f'adb -s {device_id} shell pm list packages' pattern = r"(.*)(com.uma.(.*))" process = subprocess.Popen(commands.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd='.') @@ -292,7 +293,8 @@ def AppEviction(self, device_id): except Exception as e: Log.E(f"DECODING EXCEPTION: {e}") - def TapEviction(self): + @staticmethod + def TapEviction(): if platform.system() == 'Linux': pass elif platform.system() == 'Windows': diff --git a/Helper/cli_executor.py b/Helper/cli_executor.py index 1b8f0ce..38712c5 100644 --- a/Helper/cli_executor.py +++ b/Helper/cli_executor.py @@ -4,16 +4,15 @@ class Cli: - def __init__(self, parameters: List[str], cwd: str, logger: Callable): + def __init__(self, parameters, cwd: str, logger: Callable): - aux_list = list(map(str.split, parameters)) - self.parameters = [elem for sublist in aux_list for elem in sublist] + self.parameters = parameters self.cwd = cwd self.logger = logger def Execute(self) -> int: process = subprocess.Popen(self.parameters, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, cwd=self.cwd) + stderr=subprocess.STDOUT, cwd=self.cwd, shell=True) self.stdout(process) return process.wait() From 13af3a2f58ceaa16f8eae059212e9912af68f99b Mon Sep 17 00:00:00 2001 From: JorgeMO-sudo Date: Wed, 8 May 2024 11:25:08 +0200 Subject: [PATCH 14/14] Minor changes --- install.sh | 0 start.sh | 0 test.sh | 3 +++ 3 files changed, 3 insertions(+) mode change 100644 => 100755 install.sh mode change 100644 => 100755 start.sh create mode 100755 test.sh diff --git a/install.sh b/install.sh old mode 100644 new mode 100755 diff --git a/start.sh b/start.sh old mode 100644 new mode 100755 diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..fce7212 --- /dev/null +++ b/test.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +echo "Hola Mundo !!!"