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
20 import functest.utils.functest_utils as ft_utils
23 def finish_session(current_scenario):
24 """Finish a recording session."""
25 if current_scenario is None:
28 EnergyRecorder.submit_scenario(
29 current_scenario["scenario"],
30 current_scenario["step"]
34 def enable_recording(method):
36 Record energy during method execution.
38 Decorator to record energy during "method" exection.
40 param method: Method to suround with start and stop
41 :type method: function
43 .. note:: "method" should belong to a class having a "case_name"
49 Record energy during method execution (implementation).
51 Wrapper for decorator to handle method arguments.
53 current_scenario = EnergyRecorder.get_current_scenario()
54 EnergyRecorder.start(args[0].case_name)
56 return_value = method(*args)
57 finish_session(current_scenario)
58 except Exception as exc: # pylint: disable=broad-except
59 EnergyRecorder.logger.exception(exc)
60 finish_session(current_scenario)
66 # Class to manage energy recording sessions
67 class EnergyRecorder(object):
68 """Manage Energy recording session."""
70 logger = logging.getLogger(__name__)
71 # Energy recording API connectivity settings
72 # see load_config method
73 energy_recorder_api = None
75 # Default initial step
76 INITIAL_STEP = "running"
78 # Default connection timeout
84 Load connectivity settings from yaml.
86 Load connectivity settings to Energy recording API
87 Use functest global config yaml file
88 (see functest_utils.get_functest_config)
90 # Singleton pattern for energy_recorder_api static member
91 # Load only if not previouly done
92 if EnergyRecorder.energy_recorder_api is None:
93 environment = ft_utils.get_pod_name()
96 energy_recorder_uri = ft_utils.get_functest_config(
97 "energy_recorder.api_url")
98 assert energy_recorder_uri
101 uri_comp = "/recorders/environment/"
102 uri_comp += urllib.quote_plus(environment)
103 EnergyRecorder.logger.debug(
104 "API recorder at: " + energy_recorder_uri + uri_comp)
107 user = ft_utils.get_functest_config(
108 "energy_recorder.api_user")
109 password = ft_utils.get_functest_config(
110 "energy_recorder.api_password")
112 if user != "" and password != "":
113 energy_recorder_api_auth = (user, password)
115 energy_recorder_api_auth = None
118 resp = requests.get(energy_recorder_uri + "/monitoring/ping",
119 auth=energy_recorder_api_auth,
121 'content-type': 'application/json'
123 timeout=EnergyRecorder.CONNECTION_TIMOUT)
124 api_available = json.loads(resp.text)["status"] == "OK"
125 except Exception: # pylint: disable=broad-except
126 EnergyRecorder.logger.error(
127 "Energy recorder API is not available")
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")
158 # Call API to start energy recording
159 response = requests.post(
160 EnergyRecorder.energy_recorder_api["uri"],
161 data=json.dumps(payload),
162 auth=EnergyRecorder.energy_recorder_api["auth"],
164 'content-type': 'application/json'
166 timeout=EnergyRecorder.CONNECTION_TIMOUT
168 if response.status_code != 200:
169 EnergyRecorder.logger.error(
170 "Error while submitting scenario\n%s",
172 return_status = False
173 except requests.exceptions.ConnectionError:
174 EnergyRecorder.logger.warning(
175 "submit_scenario: Unable to connect energy recorder API")
176 return_status = False
177 except Exception: # pylint: disable=broad-except
178 # Default exception handler to ensure that method
180 EnergyRecorder.logger.exception(
181 "Error while submitting scenarion to energy recorder API"
183 return_status = False
189 Start a recording session for scenario.
191 param scenario: Starting scenario
192 :type scenario: string
196 if EnergyRecorder.load_config():
197 EnergyRecorder.logger.debug("Starting recording")
198 return_status = EnergyRecorder.submit_scenario(
200 EnergyRecorder.INITIAL_STEP
203 except Exception: # pylint: disable=broad-except
204 # Default exception handler to ensure that method
206 EnergyRecorder.logger.exception(
207 "Error while starting energy recorder API"
209 return_status = False
214 """Stop current recording session."""
217 # Ensure that connectyvity settings are loaded
218 if EnergyRecorder.load_config():
219 EnergyRecorder.logger.debug("Stopping recording")
221 # Call API to stop energy recording
222 response = requests.delete(
223 EnergyRecorder.energy_recorder_api["uri"],
224 auth=EnergyRecorder.energy_recorder_api["auth"],
226 'content-type': 'application/json'
228 timeout=EnergyRecorder.CONNECTION_TIMOUT
230 if response.status_code != 200:
231 EnergyRecorder.logger.error(
232 "Error while stating energy recording session\n%s",
234 return_status = False
235 except requests.exceptions.ConnectionError:
236 EnergyRecorder.logger.warning(
237 "stop: Unable to connect energy recorder API")
238 return_status = False
239 except Exception: # pylint: disable=broad-except
240 # Default exception handler to ensure that method
242 EnergyRecorder.logger.exception(
243 "Error while stoping energy recorder API"
245 return_status = False
250 """Notify energy recording service of current step of the testcase."""
253 # Ensure that connectyvity settings are loaded
254 if EnergyRecorder.load_config():
255 EnergyRecorder.logger.debug("Setting step")
262 # Call API to define step
263 response = requests.post(
264 EnergyRecorder.energy_recorder_api["uri"] + "/step",
265 data=json.dumps(payload),
266 auth=EnergyRecorder.energy_recorder_api["auth"],
268 'content-type': 'application/json'
270 timeout=EnergyRecorder.CONNECTION_TIMOUT
272 if response.status_code != 200:
273 EnergyRecorder.logger.error(
274 "Error while setting current step of testcase\n%s",
276 return_status = False
277 except requests.exceptions.ConnectionError:
278 EnergyRecorder.logger.warning(
279 "set_step: Unable to connect energy recorder API")
280 return_status = False
281 except Exception: # pylint: disable=broad-except
282 # Default exception handler to ensure that method
284 EnergyRecorder.logger.exception(
285 "Error while setting step on energy recorder API"
287 return_status = False
291 def get_current_scenario():
292 """Get current running scenario (if any, None else)."""
295 # Ensure that connectyvity settings are loaded
296 if EnergyRecorder.load_config():
297 EnergyRecorder.logger.debug("Getting current scenario")
299 # Call API get running scenario
300 response = requests.get(
301 EnergyRecorder.energy_recorder_api["uri"],
302 auth=EnergyRecorder.energy_recorder_api["auth"],
303 timeout=EnergyRecorder.CONNECTION_TIMOUT
305 if response.status_code == 200:
306 return_value = json.loads(response.text)
307 elif response.status_code == 404:
308 EnergyRecorder.logger.info(
309 "No current running scenario at %s",
310 EnergyRecorder.energy_recorder_api["uri"])
313 EnergyRecorder.logger.error(
314 "Error while getting current scenario\n%s",
317 except requests.exceptions.ConnectionError:
318 EnergyRecorder.logger.warning(
319 "get_currernt_sceario: Unable to connect energy recorder API")
321 except Exception: # pylint: disable=broad-except
322 # Default exception handler to ensure that method
324 EnergyRecorder.logger.exception(
325 "Error while getting current scenario from energy recorder API"