2 # -*- coding: UTF-8 -*-
4 # Copyright (c) 2017 Orange and others.
6 # All rights reserved. This program and the accompanying materials
7 # are made available under the terms of the Apache License, Version 2.0
8 # which accompanies this distribution, and is available at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 """This module manages calls to Energy recording API."""
18 from functools import wraps
20 from six.moves import urllib
23 def finish_session(current_scenario):
24 """Finish a recording session."""
25 if current_scenario is None:
28 EnergyRecorder.logger.debug("Restoring previous scenario (%s/%s)",
29 current_scenario["scenario"],
30 current_scenario["step"])
31 EnergyRecorder.submit_scenario(
32 current_scenario["scenario"],
33 current_scenario["step"]
37 def enable_recording(method):
39 Record energy during method execution.
41 Decorator to record energy during "method" exection.
43 param method: Method to suround with start and stop
44 :type method: function
46 .. note:: "method" should belong to a class having a "case_name"
52 Record energy during method execution (implementation).
54 Wrapper for decorator to handle method arguments.
56 current_scenario = EnergyRecorder.get_current_scenario()
57 EnergyRecorder.start(args[0].case_name)
59 return_value = method(*args)
60 finish_session(current_scenario)
61 except Exception as exc: # pylint: disable=broad-except
62 EnergyRecorder.logger.exception(exc)
63 finish_session(current_scenario)
69 # Class to manage energy recording sessions
70 class EnergyRecorder(object):
71 """Manage Energy recording session."""
73 logger = logging.getLogger(__name__)
74 # Energy recording API connectivity settings
75 # see load_config method
76 energy_recorder_api = None
78 # Default initial step
79 INITIAL_STEP = "running"
81 # Default connection timeout
82 CONNECTION_TIMEOUT = 4
87 Load connectivity settings from yaml.
89 Load connectivity settings to Energy recording API
90 Use functest global config yaml file
91 (see functest_utils.get_functest_config)
93 # Singleton pattern for energy_recorder_api static member
94 # Load only if not previouly done
95 if EnergyRecorder.energy_recorder_api is None:
96 assert os.environ['NODE_NAME']
97 assert os.environ["ENERGY_RECORDER_API_URL"]
98 environment = os.environ['NODE_NAME']
99 energy_recorder_uri = os.environ["ENERGY_RECORDER_API_URL"]
102 creds_usr = os.environ.get("ENERGY_RECORDER_API_USER", "")
103 creds_pass = os.environ.get("ENERGY_RECORDER_API_PASSWORD", "")
105 uri_comp = "/recorders/environment/"
106 uri_comp += urllib.parse.quote_plus(environment)
108 if creds_usr != "" and creds_pass != "":
109 energy_recorder_api_auth = (creds_usr, creds_pass)
111 energy_recorder_api_auth = None
114 resp = requests.get(energy_recorder_uri + "/monitoring/ping",
115 auth=energy_recorder_api_auth,
117 'content-type': 'application/json'
119 timeout=EnergyRecorder.CONNECTION_TIMEOUT)
120 api_available = json.loads(resp.text)["status"] == "OK"
121 EnergyRecorder.logger.info(
122 "API recorder available at : %s",
123 energy_recorder_uri + uri_comp)
124 except Exception as exc: # pylint: disable=broad-except
125 EnergyRecorder.logger.info(
126 "Energy recorder API is not available, cause=%s",
128 api_available = False
130 EnergyRecorder.energy_recorder_api = {
131 "uri": energy_recorder_uri + uri_comp,
132 "auth": energy_recorder_api_auth,
133 "available": api_available
135 return EnergyRecorder.energy_recorder_api["available"]
138 def submit_scenario(scenario, step):
140 Submit a complet scenario definition to Energy recorder API.
142 param scenario: Scenario name
143 :type scenario: string
144 param step: Step name
149 # Ensure that connectyvity settings are loaded
150 if EnergyRecorder.load_config():
151 EnergyRecorder.logger.debug("Submitting scenario (%s/%s)",
159 # Call API to start energy recording
160 response = requests.post(
161 EnergyRecorder.energy_recorder_api["uri"],
162 data=json.dumps(payload),
163 auth=EnergyRecorder.energy_recorder_api["auth"],
165 'content-type': 'application/json'
167 timeout=EnergyRecorder.CONNECTION_TIMEOUT
169 if response.status_code != 200:
170 EnergyRecorder.logger.error(
171 "Error while submitting scenario\n%s",
173 return_status = False
174 except requests.exceptions.ConnectionError:
175 EnergyRecorder.logger.warning(
176 "submit_scenario: Unable to connect energy recorder API")
177 return_status = False
178 except Exception: # pylint: disable=broad-except
179 # Default exception handler to ensure that method
181 EnergyRecorder.logger.info(
182 "Error while submitting scenarion to energy recorder API\n%s",
183 traceback.format_exc()
185 return_status = False
191 Start a recording session for scenario.
193 param scenario: Starting scenario
194 :type scenario: string
198 if EnergyRecorder.load_config():
199 EnergyRecorder.logger.debug("Starting recording")
200 return_status = EnergyRecorder.submit_scenario(
202 EnergyRecorder.INITIAL_STEP
205 except Exception: # pylint: disable=broad-except
206 # Default exception handler to ensure that method
208 EnergyRecorder.logger.info(
209 "Error while starting energy recorder API\n%s",
210 traceback.format_exc()
212 return_status = False
217 """Stop current recording session."""
220 # Ensure that connectyvity settings are loaded
221 if EnergyRecorder.load_config():
222 EnergyRecorder.logger.debug("Stopping recording")
224 # Call API to stop energy recording
225 response = requests.delete(
226 EnergyRecorder.energy_recorder_api["uri"],
227 auth=EnergyRecorder.energy_recorder_api["auth"],
229 'content-type': 'application/json'
231 timeout=EnergyRecorder.CONNECTION_TIMEOUT
233 if response.status_code != 200:
234 EnergyRecorder.logger.error(
235 "Error while stating energy recording session\n%s",
237 return_status = False
238 except requests.exceptions.ConnectionError:
239 EnergyRecorder.logger.warning(
240 "stop: Unable to connect energy recorder API")
241 return_status = False
242 except Exception: # pylint: disable=broad-except
243 # Default exception handler to ensure that method
245 EnergyRecorder.logger.info(
246 "Error while stoping energy recorder API\n%s",
247 traceback.format_exc()
249 return_status = False
254 """Notify energy recording service of current step of the testcase."""
257 # Ensure that connectyvity settings are loaded
258 if EnergyRecorder.load_config():
259 EnergyRecorder.logger.debug("Setting step")
266 # Call API to define step
267 response = requests.post(
268 EnergyRecorder.energy_recorder_api["uri"] + "/step",
269 data=json.dumps(payload),
270 auth=EnergyRecorder.energy_recorder_api["auth"],
272 'content-type': 'application/json'
274 timeout=EnergyRecorder.CONNECTION_TIMEOUT
276 if response.status_code != 200:
277 EnergyRecorder.logger.error(
278 "Error while setting current step of testcase\n%s",
280 return_status = False
281 except requests.exceptions.ConnectionError:
282 EnergyRecorder.logger.warning(
283 "set_step: Unable to connect energy recorder API")
284 return_status = False
285 except Exception: # pylint: disable=broad-except
286 # Default exception handler to ensure that method
288 EnergyRecorder.logger.info(
289 "Error while setting step on energy recorder API\n%s",
290 traceback.format_exc()
292 return_status = False
296 def get_current_scenario():
297 """Get current running scenario (if any, None else)."""
300 # Ensure that connectyvity settings are loaded
301 if EnergyRecorder.load_config():
302 EnergyRecorder.logger.debug("Getting current scenario")
304 # Call API get running scenario
305 response = requests.get(
306 EnergyRecorder.energy_recorder_api["uri"],
307 auth=EnergyRecorder.energy_recorder_api["auth"],
308 timeout=EnergyRecorder.CONNECTION_TIMEOUT
310 if response.status_code == 200:
311 return_value = json.loads(response.text)
312 elif response.status_code == 404:
313 EnergyRecorder.logger.info(
314 "No current running scenario at %s",
315 EnergyRecorder.energy_recorder_api["uri"])
318 EnergyRecorder.logger.error(
319 "Error while getting current scenario\n%s",
322 except requests.exceptions.ConnectionError:
323 EnergyRecorder.logger.warning(
324 "get_currernt_sceario: Unable to connect energy recorder API")
326 except Exception: # pylint: disable=broad-except
327 # Default exception handler to ensure that method
329 EnergyRecorder.logger.info(
330 "Error while getting current scenario from energy recorder API"
331 "\n%s", traceback.format_exc()