import json
import logging
import urllib
+
+from functools import wraps
import requests
+import urllib3
import functest.utils.functest_utils as ft_utils
+def finish_session(current_scenario):
+ """Finish a recording session."""
+ if current_scenario is None:
+ EnergyRecorder.stop()
+ else:
+ EnergyRecorder.submit_scenario(
+ current_scenario["scenario"],
+ current_scenario["step"]
+ )
+
+
def enable_recording(method):
"""
+ Record energy during method execution.
+
Decorator to record energy during "method" exection.
param method: Method to suround with start and stop
.. note:: "method" should belong to a class having a "case_name"
attribute
"""
+ @wraps(method)
def wrapper(*args):
- """Wrapper for decorator to handle method arguments."""
+ """
+ Record energy during method execution (implementation).
+
+ Wrapper for decorator to handle method arguments.
+ """
+ current_scenario = EnergyRecorder.get_current_scenario()
EnergyRecorder.start(args[0].case_name)
- return_value = method(*args)
- EnergyRecorder.stop()
+ try:
+ return_value = method(*args)
+ finish_session(current_scenario)
+ except Exception as exc: # pylint: disable=broad-except
+ EnergyRecorder.logger.exception(exc)
+ finish_session(current_scenario)
+ raise exc
return return_value
return wrapper
energy_recorder_api = None
# Default initial step
- INITIAL_STEP = "starting"
+ INITIAL_STEP = "running"
+
+ # Default connection timeout
+ CONNECTION_TIMOUT = urllib3.Timeout(connect=1, read=3)
@staticmethod
def load_config():
assert energy_recorder_uri
assert environment
- energy_recorder_uri += "/recorders/environment/"
- energy_recorder_uri += urllib.quote_plus(environment)
+ uri_comp = "/recorders/environment/"
+ uri_comp += urllib.quote_plus(environment)
EnergyRecorder.logger.debug(
- "API recorder at: " + energy_recorder_uri)
+ "API recorder at: " + energy_recorder_uri + uri_comp)
# Creds
- user = ft_utils.get_functest_config(
+ creds_usr = ft_utils.get_functest_config(
"energy_recorder.api_user")
- password = ft_utils.get_functest_config(
+ creds_pass = ft_utils.get_functest_config(
"energy_recorder.api_password")
- if user != "" and password != "":
- energy_recorder_api_auth = (user, password)
+ if creds_usr != "" and creds_pass != "":
+ energy_recorder_api_auth = (creds_usr, creds_pass)
else:
energy_recorder_api_auth = None
+ try:
+ resp = requests.get(energy_recorder_uri + "/monitoring/ping",
+ auth=energy_recorder_api_auth,
+ headers={
+ 'content-type': 'application/json'
+ },
+ timeout=EnergyRecorder.CONNECTION_TIMOUT)
+ api_available = json.loads(resp.text)["status"] == "OK"
+ except Exception: # pylint: disable=broad-except
+ EnergyRecorder.logger.error(
+ "Energy recorder API is not available")
+ api_available = False
# Final config
EnergyRecorder.energy_recorder_api = {
- "uri": energy_recorder_uri,
- "auth": energy_recorder_api_auth
+ "uri": energy_recorder_uri + uri_comp,
+ "auth": energy_recorder_api_auth,
+ "available": api_available
}
+ return EnergyRecorder.energy_recorder_api["available"]
@staticmethod
- def start(scenario):
+ def submit_scenario(scenario, step):
"""
- Start a recording session for scenario.
+ Submit a complet scenario definition to Energy recorder API.
- param scenario: Starting scenario
+ param scenario: Scenario name
:type scenario: string
+ param step: Step name
+ :type step: string
"""
- return_status = True
try:
- EnergyRecorder.logger.debug("Starting recording")
+ return_status = True
# Ensure that connectyvity settings are loaded
- EnergyRecorder.load_config()
+ if EnergyRecorder.load_config():
+ EnergyRecorder.logger.debug("Submitting scenario")
- # Create API payload
- payload = {
- "step": EnergyRecorder.INITIAL_STEP,
- "scenario": scenario
- }
- # Call API to start energy recording
- response = requests.post(
- EnergyRecorder.energy_recorder_api["uri"],
- data=json.dumps(payload),
- auth=EnergyRecorder.energy_recorder_api["auth"],
- headers={
- 'content-type': 'application/json'
+ # Create API payload
+ payload = {
+ "step": step,
+ "scenario": scenario
}
+ # Call API to start energy recording
+ response = requests.post(
+ EnergyRecorder.energy_recorder_api["uri"],
+ data=json.dumps(payload),
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ },
+ timeout=EnergyRecorder.CONNECTION_TIMOUT
+ )
+ if response.status_code != 200:
+ EnergyRecorder.logger.error(
+ "Error while submitting scenario\n%s",
+ response.text)
+ return_status = False
+ except requests.exceptions.ConnectionError:
+ EnergyRecorder.logger.warning(
+ "submit_scenario: Unable to connect energy recorder API")
+ return_status = False
+ except Exception: # pylint: disable=broad-except
+ # Default exception handler to ensure that method
+ # is safe for caller
+ EnergyRecorder.logger.exception(
+ "Error while submitting scenarion to energy recorder API"
)
- if response.status_code != 200:
- log_msg = "Error while starting energy recording session\n{}"
- log_msg = log_msg.format(response.text)
- EnergyRecorder.logger.info(log_msg)
- return_status = False
+ return_status = False
+ return return_status
+
+ @staticmethod
+ def start(scenario):
+ """
+ Start a recording session for scenario.
+
+ param scenario: Starting scenario
+ :type scenario: string
+ """
+ return_status = True
+ try:
+ if EnergyRecorder.load_config():
+ EnergyRecorder.logger.debug("Starting recording")
+ return_status = EnergyRecorder.submit_scenario(
+ scenario,
+ EnergyRecorder.INITIAL_STEP
+ )
except Exception: # pylint: disable=broad-except
# Default exception handler to ensure that method
@staticmethod
def stop():
"""Stop current recording session."""
- EnergyRecorder.logger.debug("Stopping recording")
return_status = True
try:
# Ensure that connectyvity settings are loaded
- EnergyRecorder.load_config()
-
- # Call API to stop energy recording
- response = requests.delete(
- EnergyRecorder.energy_recorder_api["uri"],
- auth=EnergyRecorder.energy_recorder_api["auth"],
- headers={
- 'content-type': 'application/json'
- }
- )
- if response.status_code != 200:
- log_msg = "Error while stating energy recording session\n{}"
- log_msg = log_msg.format(response.text)
- EnergyRecorder.logger.error(log_msg)
- return_status = False
+ if EnergyRecorder.load_config():
+ EnergyRecorder.logger.debug("Stopping recording")
+
+ # Call API to stop energy recording
+ response = requests.delete(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ },
+ timeout=EnergyRecorder.CONNECTION_TIMOUT
+ )
+ if response.status_code != 200:
+ EnergyRecorder.logger.error(
+ "Error while stating energy recording session\n%s",
+ response.text)
+ return_status = False
+ except requests.exceptions.ConnectionError:
+ EnergyRecorder.logger.warning(
+ "stop: Unable to connect energy recorder API")
+ return_status = False
except Exception: # pylint: disable=broad-except
# Default exception handler to ensure that method
# is safe for caller
@staticmethod
def set_step(step):
"""Notify energy recording service of current step of the testcase."""
- EnergyRecorder.logger.debug("Setting step")
return_status = True
try:
# Ensure that connectyvity settings are loaded
- EnergyRecorder.load_config()
+ if EnergyRecorder.load_config():
+ EnergyRecorder.logger.debug("Setting step")
- # Create API payload
- payload = {
- "step": step,
- }
-
- # Call API to define step
- response = requests.post(
- EnergyRecorder.energy_recorder_api["uri"] + "/step",
- data=json.dumps(payload),
- auth=EnergyRecorder.energy_recorder_api["auth"],
- headers={
- 'content-type': 'application/json'
+ # Create API payload
+ payload = {
+ "step": step,
}
- )
- if response.status_code != 200:
- log_msg = "Error while setting current step of testcase\n{}"
- log_msg = log_msg.format(response.text)
- EnergyRecorder.logger.error(log_msg)
- return_status = False
+
+ # Call API to define step
+ response = requests.post(
+ EnergyRecorder.energy_recorder_api["uri"] + "/step",
+ data=json.dumps(payload),
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ headers={
+ 'content-type': 'application/json'
+ },
+ timeout=EnergyRecorder.CONNECTION_TIMOUT
+ )
+ if response.status_code != 200:
+ EnergyRecorder.logger.error(
+ "Error while setting current step of testcase\n%s",
+ response.text)
+ return_status = False
+ except requests.exceptions.ConnectionError:
+ EnergyRecorder.logger.warning(
+ "set_step: Unable to connect energy recorder API")
+ return_status = False
except Exception: # pylint: disable=broad-except
# Default exception handler to ensure that method
# is safe for caller
)
return_status = False
return return_status
+
+ @staticmethod
+ def get_current_scenario():
+ """Get current running scenario (if any, None else)."""
+ return_value = None
+ try:
+ # Ensure that connectyvity settings are loaded
+ if EnergyRecorder.load_config():
+ EnergyRecorder.logger.debug("Getting current scenario")
+
+ # Call API get running scenario
+ response = requests.get(
+ EnergyRecorder.energy_recorder_api["uri"],
+ auth=EnergyRecorder.energy_recorder_api["auth"],
+ timeout=EnergyRecorder.CONNECTION_TIMOUT
+ )
+ if response.status_code == 200:
+ return_value = json.loads(response.text)
+ elif response.status_code == 404:
+ EnergyRecorder.logger.info(
+ "No current running scenario at %s",
+ EnergyRecorder.energy_recorder_api["uri"])
+ return_value = None
+ else:
+ EnergyRecorder.logger.error(
+ "Error while getting current scenario\n%s",
+ response.text)
+ return_value = None
+ except requests.exceptions.ConnectionError:
+ EnergyRecorder.logger.warning(
+ "get_currernt_sceario: Unable to connect energy recorder API")
+ return_value = None
+ except Exception: # pylint: disable=broad-except
+ # Default exception handler to ensure that method
+ # is safe for caller
+ EnergyRecorder.logger.exception(
+ "Error while getting current scenario from energy recorder API"
+ )
+ return_value = None
+ return return_value