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."""
17 from functools import wraps
19 from six.moves import urllib
21 from functest.utils import env
24 def finish_session(current_scenario):
25 """Finish a recording session."""
26 if current_scenario is None:
29 EnergyRecorder.logger.debug("Restoring previous scenario (%s/%s)",
30 current_scenario["scenario"],
31 current_scenario["step"])
32 EnergyRecorder.submit_scenario(
33 current_scenario["scenario"],
34 current_scenario["step"]
38 def enable_recording(method):
40 Record energy during method execution.
42 Decorator to record energy during "method" exection.
44 param method: Method to suround with start and stop
45 :type method: function
47 .. note:: "method" should belong to a class having a "case_name"
53 Record energy during method execution (implementation).
55 Wrapper for decorator to handle method arguments.
57 current_scenario = EnergyRecorder.get_current_scenario()
58 EnergyRecorder.start(args[0].case_name)
60 return_value = method(*args)
61 finish_session(current_scenario)
62 except Exception as exc: # pylint: disable=broad-except
63 EnergyRecorder.logger.exception(exc)
64 finish_session(current_scenario)
70 # Class to manage energy recording sessions
71 class EnergyRecorder(object):
72 """Manage Energy recording session."""
74 logger = logging.getLogger(__name__)
75 # Energy recording API connectivity settings
76 # see load_config method
77 energy_recorder_api = None
79 # Default initial step
80 INITIAL_STEP = "running"
82 # Default connection timeout
83 CONNECTION_TIMEOUT = 4
88 Load connectivity settings from yaml.
90 Load connectivity settings to Energy recording API
91 Use functest global config yaml file
92 (see functest_utils.get_functest_config)
94 # Singleton pattern for energy_recorder_api static member
95 # Load only if not previouly done
96 if EnergyRecorder.energy_recorder_api is None:
97 assert env.get('NODE_NAME')
98 assert env.get('ENERGY_RECORDER_API_URL')
99 environment = env.get('NODE_NAME')
100 energy_recorder_uri = env.get(
101 'ENERGY_RECORDER_API_URL')
104 creds_usr = env.get("ENERGY_RECORDER_API_USER")
105 creds_pass = env.get("ENERGY_RECORDER_API_PASSWORD")
107 uri_comp = "/recorders/environment/"
108 uri_comp += urllib.parse.quote_plus(environment)
110 if creds_usr and creds_pass:
111 energy_recorder_api_auth = (creds_usr, creds_pass)
113 energy_recorder_api_auth = None
116 resp = requests.get(energy_recorder_uri + "/monitoring/ping",
117 auth=energy_recorder_api_auth,
119 'content-type': 'application/json'
121 timeout=EnergyRecorder.CONNECTION_TIMEOUT)
122 api_available = json.loads(resp.text)["status"] == "OK"
123 EnergyRecorder.logger.info(
124 "API recorder available at : %s",
125 energy_recorder_uri + uri_comp)
126 except Exception as exc: # pylint: disable=broad-except
127 EnergyRecorder.logger.info(
128 "Energy recorder API is not available, cause=%s",
130 api_available = False
132 EnergyRecorder.energy_recorder_api = {
133 "uri": energy_recorder_uri + uri_comp,
134 "auth": energy_recorder_api_auth,
135 "available": api_available
137 return EnergyRecorder.energy_recorder_api["available"]
140 def submit_scenario(scenario, step):
142 Submit a complet scenario definition to Energy recorder API.
144 param scenario: Scenario name
145 :type scenario: string
146 param step: Step name
151 # Ensure that connectyvity settings are loaded
152 if EnergyRecorder.load_config():
153 EnergyRecorder.logger.debug("Submitting scenario (%s/%s)",
161 # Call API to start energy recording
162 response = requests.post(
163 EnergyRecorder.energy_recorder_api["uri"],
164 data=json.dumps(payload),
165 auth=EnergyRecorder.energy_recorder_api["auth"],
167 'content-type': 'application/json'
169 timeout=EnergyRecorder.CONNECTION_TIMEOUT
171 if response.status_code != 200:
172 EnergyRecorder.logger.error(
173 "Error while submitting scenario\n%s",
175 return_status = False
176 except requests.exceptions.ConnectionError:
177 EnergyRecorder.logger.warning(
178 "submit_scenario: Unable to connect energy recorder API")
179 return_status = False
180 except Exception: # pylint: disable=broad-except
181 # Default exception handler to ensure that method
183 EnergyRecorder.logger.info(
184 "Error while submitting scenarion to energy recorder API\n%s",
185 traceback.format_exc()
187 return_status = False
193 Start a recording session for scenario.
195 param scenario: Starting scenario
196 :type scenario: string
200 if EnergyRecorder.load_config():
201 EnergyRecorder.logger.debug("Starting recording")
202 return_status = EnergyRecorder.submit_scenario(
204 EnergyRecorder.INITIAL_STEP
207 except Exception: # pylint: disable=broad-except
208 # Default exception handler to ensure that method
210 EnergyRecorder.logger.info(
211 "Error while starting energy recorder API\n%s",
212 traceback.format_exc()
214 return_status = False
219 """Stop current recording session."""
222 # Ensure that connectyvity settings are loaded
223 if EnergyRecorder.load_config():
224 EnergyRecorder.logger.debug("Stopping recording")
226 # Call API to stop energy recording
227 response = requests.delete(
228 EnergyRecorder.energy_recorder_api["uri"],
229 auth=EnergyRecorder.energy_recorder_api["auth"],
231 'content-type': 'application/json'
233 timeout=EnergyRecorder.CONNECTION_TIMEOUT
235 if response.status_code != 200:
236 EnergyRecorder.logger.error(
237 "Error while stating energy recording session\n%s",
239 return_status = False
240 except requests.exceptions.ConnectionError:
241 EnergyRecorder.logger.warning(
242 "stop: Unable to connect energy recorder API")
243 return_status = False
244 except Exception: # pylint: disable=broad-except
245 # Default exception handler to ensure that method
247 EnergyRecorder.logger.info(
248 "Error while stoping energy recorder API\n%s",
249 traceback.format_exc()
251 return_status = False
256 """Notify energy recording service of current step of the testcase."""
259 # Ensure that connectyvity settings are loaded
260 if EnergyRecorder.load_config():
261 EnergyRecorder.logger.debug("Setting step")
268 # Call API to define step
269 response = requests.post(
270 EnergyRecorder.energy_recorder_api["uri"] + "/step",
271 data=json.dumps(payload),
272 auth=EnergyRecorder.energy_recorder_api["auth"],
274 'content-type': 'application/json'
276 timeout=EnergyRecorder.CONNECTION_TIMEOUT
278 if response.status_code != 200:
279 EnergyRecorder.logger.error(
280 "Error while setting current step of testcase\n%s",
282 return_status = False
283 except requests.exceptions.ConnectionError:
284 EnergyRecorder.logger.warning(
285 "set_step: Unable to connect energy recorder API")
286 return_status = False
287 except Exception: # pylint: disable=broad-except
288 # Default exception handler to ensure that method
290 EnergyRecorder.logger.info(
291 "Error while setting step on energy recorder API\n%s",
292 traceback.format_exc()
294 return_status = False
298 def get_current_scenario():
299 """Get current running scenario (if any, None else)."""
302 # Ensure that connectyvity settings are loaded
303 if EnergyRecorder.load_config():
304 EnergyRecorder.logger.debug("Getting current scenario")
306 # Call API get running scenario
307 response = requests.get(
308 EnergyRecorder.energy_recorder_api["uri"],
309 auth=EnergyRecorder.energy_recorder_api["auth"],
310 timeout=EnergyRecorder.CONNECTION_TIMEOUT
312 if response.status_code == 200:
313 return_value = json.loads(response.text)
314 elif response.status_code == 404:
315 EnergyRecorder.logger.info(
316 "No current running scenario at %s",
317 EnergyRecorder.energy_recorder_api["uri"])
320 EnergyRecorder.logger.error(
321 "Error while getting current scenario\n%s",
324 except requests.exceptions.ConnectionError:
325 EnergyRecorder.logger.warning(
326 "get_currernt_sceario: Unable to connect energy recorder API")
328 except Exception: # pylint: disable=broad-except
329 # Default exception handler to ensure that method
331 EnergyRecorder.logger.info(
332 "Error while getting current scenario from energy recorder API"
333 "\n%s", traceback.format_exc()