Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 44 additions & 5 deletions framework/python/src/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,13 +584,52 @@ async def get_report(self, response: Response,
response.status_code = 404
return self._generate_msg(False, "Report could not be found")

async def get_results(self, response: Response,
device_name, timestamp):

file_path = os.path.join(DEVICES_PATH, device_name, "reports",
timestamp, "results.zip")
async def get_results(self, request: Request,
response: Response,
device_name, timestamp):
LOGGER.debug("Received get results " +
f"request for {device_name} / {timestamp}")

profile = None

try:
req_raw = (await request.body()).decode("UTF-8")
req_json = json.loads(req_raw)

# Check if profile has been specified
if "profile" in req_json:
profile_name = req_json.get("profile")
profile = self.get_session().get_profile(profile_name)

if profile is None:
response.status_code = status.HTTP_404_NOT_FOUND
return self._generate_msg(
False,
"A profile with that name could not be found")

except JSONDecodeError:
# Profile not specified
pass

# Check if device exists
device = self.get_session().get_device_by_name(device_name)
if device is None:
response.status_code = status.HTTP_404_NOT_FOUND
return self._generate_msg(False,
"A device with that name could not be found")

file_path = self._get_test_run().get_test_orc().zip_results(
device,
timestamp,
profile
)

if file_path is None:
response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
return self._generate_msg(
False,
"An error occurred whilst archiving test results")

if os.path.isfile(file_path):
return FileResponse(file_path)
else:
Expand Down
7 changes: 7 additions & 0 deletions framework/python/src/common/risk_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
"""Stores additional information about a device's risk"""

from datetime import datetime
import os

PROFILES_PATH = 'local/risk_profiles'

class RiskProfile():
"""Python representation of a risk profile"""
Expand All @@ -40,3 +43,7 @@ def to_json(self):
'questions': self.questions
}
return json

def get_file_path(self):
return os.path.join(PROFILES_PATH,
self.name + '.json')
19 changes: 13 additions & 6 deletions framework/python/src/common/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ def set_target_device(self, device):
def get_target_device(self):
return self._device

def get_device_by_name(self, device_name):
for device in self._device_repository:
if device.device_folder.lower() == device_name.lower():
return device
return None

def get_device_repository(self):
return self._device_repository

Expand Down Expand Up @@ -374,7 +380,7 @@ def _load_profiles(self):
json_data = json.load(f)
risk_profile = RiskProfile(json_data)
risk_profile.status = self.check_profile_status(risk_profile)
self._profiles.append(risk_profile)
self._profiles.append(risk_profile)

except Exception as e:
LOGGER.error('An error occurred whilst loading risk profiles')
Expand Down Expand Up @@ -406,8 +412,7 @@ def validate_profile(self, profile_json):
for format_q in self.get_profiles_format():
if self._get_profile_question(
profile_json, format_q.get('question')) is None:
LOGGER.error(
'Missing question: ' + format_q.get('question'))
LOGGER.error('Missing question: ' + format_q.get('question'))
return False

return True
Expand Down Expand Up @@ -483,9 +488,11 @@ def update_profile(self, profile_json):
risk_profile.questions = profile_json.get('questions')

# Write file to disk
with open(os.path.join(
PROFILES_DIR, risk_profile.name + '.json'), 'w',
encoding='utf-8') as f:
with open(
os.path.join(
PROFILES_DIR,
risk_profile.name + '.json'
), 'w', encoding='utf-8') as f:
f.write(json.dumps(risk_profile.to_json()))

return risk_profile
Expand Down
2 changes: 1 addition & 1 deletion framework/python/src/core/testrun.py
Original file line number Diff line number Diff line change
Expand Up @@ -479,4 +479,4 @@ def _stop_ui(self):
if container is not None:
container.kill()
except docker.errors.NotFound:
return
return
2 changes: 2 additions & 0 deletions framework/python/src/net_orc/network_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import subprocess
import sys
import docker
import time
from docker.types import Mount
from common import logger, util
from net_orc.listener import Listener
Expand Down Expand Up @@ -281,6 +282,7 @@ def _start_device_monitor(self, device):
sniffer.start()

while sniffer.running:
time.sleep(1)
if not self._ip_ctrl.check_interface_status(
self._session.get_device_interface()):
sniffer.stop()
Expand Down
44 changes: 30 additions & 14 deletions framework/python/src/test_orc/test_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,6 @@ def run_test_modules(self):
# Move testing output from runtime to local device folder
timestamp_dir = self._timestamp_results(device)

# Archive the runtime directory
self._zip_results(timestamp_dir)

LOGGER.debug("Cleaning old test results...")
self._cleanup_old_test_results(device)

Expand Down Expand Up @@ -257,30 +254,49 @@ def _timestamp_results(self, device):

return completed_results_dir

def _zip_results(self, dest_path):
def zip_results(self,
device,
timestamp,
profile):

try:
LOGGER.debug("Archiving test results")

# Define where to save the zip file
zip_location = os.path.join(dest_path, "results")
src_path = os.path.join(LOCAL_DEVICE_REPORTS.replace(
"{device_folder}",
device.device_folder),
timestamp)

# The runtime directory to include in ZIP
path_to_zip = os.path.join(
self._root_path,
RUNTIME_DIR)
# Define where to save the zip file
zip_location = os.path.join(LOCAL_DEVICE_REPORTS.replace(
"{device_folder}", device.device_folder), timestamp
)

# Include profile if specified
if profile is not None:
LOGGER.debug(
f"Copying profile {profile.name} to results directory")
shutil.copy(profile.get_file_path(),
os.path.join(
src_path,
"profile.json"))

# Create ZIP file
shutil.make_archive(zip_location, "zip", path_to_zip)
if not os.path.exists(zip_location + ".zip"):
shutil.make_archive(zip_location, "zip", src_path)

# Check that the ZIP was successfully created
zip_file = zip_location + ".zip"
LOGGER.info(f'''Archive {'created at ' + zip_file
if os.path.exists(zip_file)
else'creation failed'}''')
if os.path.exists(zip_file)
else'creation failed'}''')

return zip_file

except Exception as error: # pylint: disable=W0703
LOGGER.error(f"Failed to create zip file: {error}")
LOGGER.error("Failed to create zip file")
LOGGER.debug(error)
return None

def test_in_progress(self):
return self._test_in_progress
Expand Down
2 changes: 1 addition & 1 deletion testing/api/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ def test_delete_device_success(empty_devices_dir, testrun): # pylint: disable=W0
print(mockito)

# Validate structure
assert all([isinstance(x, dict) for x in all_devices])
assert all(isinstance(x, dict) for x in all_devices)

# TOOO uncomment when is done
# assert set(dict_paths(mockito[0])) == set(dict_paths(all_devices[0]))
Expand Down