And a sample use case using them.
8 from os.path
import basename
10 from time
import sleep
17 default_vnc_password =
'passw0rd' 19 default_vnc_port = 5900
23 Parse command line arguments. 25 parser = argparse.ArgumentParser()
27 parser.add_argument(
'--vm', default=
'debian_jessie_auto', help=
"VM name to select for scenario recording")
28 parser.add_argument(
'--host', default=
'localhost', help=
"Reven launcher's hostname")
29 parser.add_argument(
'--port', type=int, default=8080, help=
"Reven launcher's port")
30 parser.add_argument(
'--user', default=
'reven', help=
"Reven username")
31 parser.add_argument(
'--project', default=
'sample_project', help=
"Reven project name")
32 parser.add_argument(
'--kill', action=
'store_true', help=
"close running project or abort previous scenario recording if any")
33 parser.add_argument(
'-f',
'--file', action=
'append', metavar=
'FILE', dest=
'files', default=[], help=
"add input file for scenario recording")
34 parser.add_argument(
'binary', nargs=
'?', help=
"binary to analyse (will be uploaded as input file)")
35 parser.add_argument(
'args', nargs=
'*', help=
"arguments to launch binary with")
37 return parser.parse_args()
41 def connect_to_launcher(host, port):
43 Connect to Reven's launcher. 44 On error, print and exit. 45 @param host: host to connect to. 46 @param port: port to connect to. 47 @return: Handle to launcher (reven_api.launcher_connection). 50 lc = reven_api.launcher_connection(host, port)
55 except RuntimeError
as e:
56 print(
"Could not connect to launcher at %s:%s (%s)" % (host, port, e))
59 def vm_config_by_name(launcher_connection, vm_name):
61 Get a VM config by name. 62 @param launcher_connection: launcher handle (reven_api.launcher_connection). 63 @param vm_name: Name of the config to lookup. 64 @return: VM config (reven_api.vm_info) or None if not found. 66 for vm_cfg
in launcher_connection.list_vms():
67 if vm_cfg.name == vm_name:
70 def print_available_vms(launcher_connection):
72 Print available VM configurations. 73 @param launcher_connection: launcher handle (reven_api.launcher_connection). 75 print "Available vm configs:" 76 for vm_cfg
in launcher_connection.list_vms():
77 print "\t%s (%s)" % (vm_cfg.name, vm_cfg.display)
79 def user_exists(launcher_connection, username):
81 @param launcher_connection: launcher handle (reven_api.launcher_connection). 82 @param username: Username to check for (str) 83 @return: True if a user with username exists. 85 return username
in launcher_connection.list_users()
87 def project_exists(launcher_connection, project):
89 @param launcher_connection: launcher handle (reven_api.launcher_connection). 90 @param project: Project handle to check for (reven_api.project_id) 91 @return: True if project exists. 93 return project
in launcher_connection.list_projects(project.user)
95 def check_project_not_running(launcher_connection, project, kill=False):
97 If a server is running for the given project, kill it or exit. 98 @param launcher_connection: launcher handle (reven_api.launcher_connection). 99 @param project: Project handle to check for (reven_api.project_id) 100 @param kill: If True will try to kill project's server if running. 103 project_port = launcher_connection.project_details(project).reven_server.port
110 print "Stopping running project on port %s" % project_port
111 launcher_connection.server_kill(project_port)
113 print "Project %s already running on port %s" % (project, project_port)
116 def check_project_not_recording(launcher_connection, project, kill=False):
118 If a scenario is being recorder for the project, abort it or exit. 119 @param launcher_connection: launcher handle (reven_api.launcher_connection). 120 @param project: Project handle to check for (reven_api.project_id) 121 @param kill: If True will try to abort any current scenario recording. 124 project_scenario = launcher_connection.project_scenario(project)
129 if project_scenario.is_recording:
131 print "Aborting previous scenario recording" 132 abort_recording(launcher_connection, project)
134 print "Project %s is already recording a scenario" % (project)
139 def upload_input_files(launcher_connection, project, files):
141 Upload input files to project for scenario recording. 142 @param launcher_connection: launcher handle (reven_api.launcher_connection) 143 @param project: Project to upload files to (reven_api.project_id) 144 @param files: List of file paths to be uploaded (list(str)) 145 @return: yield uploaded filepath. 147 for filepath
in files:
148 launcher_connection.project_upload_file(project, filepath)
151 class ScenarioConfigurator(object):
153 Helper class to configure scenario recording. 156 def __init__(self, vm_cfg, binary=None, args=[], dump_hint=None):
158 @param vm_cfg: VM config to use (reven_api.vm_info) 159 @param binary: Optional binary to record, filepath must be accessible (str) 160 @param args: Arguments to launch the binary with (list(str)) 161 @param dump_hint: Address or symbol in binary to start recording from (str). 163 self._sc = reven_api.scenario_recording_config()
164 self._sc.recording.is_interactive =
True 168 self._set_binary(binary, args, dump_hint)
170 def _set_vm(self, vm_cfg):
172 @param: vm_cfg: VM config to use (reven_api.vm_info) 174 self._sc.recording.vnc_password = vm_cfg.vnc_password
or default_vnc_password
175 self._sc.recording.vnc_port = vm_cfg.vnc_port
or default_vnc_port
177 self._sc.scenario.vm_config_name = vm_cfg.name
178 self._sc.scenario.system_pdb_path = vm_cfg.pdb_path
180 def _set_binary(self, binary, args=[], dump_hint=None):
181 self._sc.recording.is_interactive =
False 183 self._sc.scenario.binary_name = basename(binary)
if binary
else '' 184 self._sc.scenario.binary_arguments =
' '.join(args)
185 self._sc.scenario.binary_dump_hint = dump_hint
or '' 186 self._sc.scenario.binary_dump_address = dump_hint
or '' 190 @return: Scenario configuration (reven_api.scenario_recording_config) 194 def stop_recording(vnc_host, vnc_port, vnc_password):
196 Gracefully stop scenario recording using VNC to send magic key sequence 'F9', 'F7'. 197 @param vnc_host: hostname to connect to. 198 @param vnc_port: port to connect to. 199 @param vnc_password: password to use. 201 from vncdotool
import api
as vnc
203 vnc.connect(
'%s::%s' % (vnc_host, vnc_port), vnc_password).keyDown(
'f9').keyDown(
'f7')
207 def abort_recording(launcher_connection, project):
209 Abort scenario recording for given project (will discard currently recorded data). 210 @param launcher_connection: launcher handle (reven_api.launcher_connection) 211 @param project: project to abort recording for (reven_api.project_id) 213 launcher_connection.project_abort_scenario_recording(project)
215 def watch_recording(launcher_connection, project):
217 @param launcher_connection: launcher handle (reven_api.launcher_connection) 218 @param project: project to watch recording (reven_api.project_id) 219 @return: yield recording progress (reven_api.scenario_recording_info) 223 progress = launcher_connection.project_scenario(project)
224 recording = progress.is_recording
228 def wait_recording(launcher_connection, project, soft_timeout=10, hard_timeout=30):
230 Blocks until scenario is recorded or stopped. 231 @param launcher_connection: launcher handle (reven_api.launcher_connection) 232 @param project: project to wait recording (reven_api.project_id) 233 @param soft_timeout: Timeout in seconds before trying to stop scenario recording 234 @param hard_timeout: Timeout in seconds before trying to abort scenario recording (recorded data are discarded) 236 for i, progress
in enumerate(watch_recording(launcher_connection, project)):
237 if progress.log_chunk:
238 print progress.log_chunk
240 if i == soft_timeout:
241 print "Soft timeout: stopping scenario recording" 243 stop_recording(launcher_connection.hostname, vnc_port, vnc_password)
244 except Exception
as e:
245 print "Could not gracefully stop recording through vnc (%s)" % e
246 elif i == hard_timeout:
247 print "Hard timeout: aborting scenario recording" 248 abort_recording(launcher_connection, project)
252 return progress.is_successful
256 def open_project(launcher_connection, project):
258 Open project (launch a server) 259 @param launcher_connection: launcher handle (reven_api.launcher_connection) 260 @param project: project to open (reven_api.project_id) 261 @return: handle to project (reven.Project) 264 port = launcher_connection.server_launch(project)
266 print "Error server not started for project %s" % project
268 print "Server started on port %s" % port
275 client = reven.Project(launcher_connection.hostname, port)
278 except RuntimeError
as e:
279 print "Could not connect (%s)" % e
285 def wait_execution(reven_client):
287 Block until execution is completed. 288 @param reven_client: opened project handle (reven.Project) 291 progress = reven_client.execution_status()
293 print "# %s/%s - %s/%s - %s" % (
294 progress.tsc, progress.last_tsc,
295 progress.point_index, progress.last_point_index,
298 if not progress.is_busy:
304 if __name__ ==
'__main__':
309 launcher_hostname = args.host
310 launcher_port = args.port
311 sample_project = reven_api.project_id(args.user, args.project)
312 sample_binary = args.binary
313 sample_binary_arguments = args.args
314 sample_input_files = args.files
316 sample_overkill = args.kill
318 sample_is_interactive =
not sample_binary
322 print "Connecting to %s:%s" % (launcher_hostname, launcher_port)
324 lc = connect_to_launcher(launcher_hostname, launcher_port)
328 vm_cfg = vm_config_by_name(lc, sample_vm)
330 print "Vm config %s not found." % (sample_vm)
331 print_available_vms(lc)
334 print "Using vm config %s: %s" % (sample_vm, vm_cfg.display)
338 if not user_exists(lc, sample_project.user):
339 print "User %s does not exist (will be created)" % sample_project.user
341 if project_exists(lc, sample_project):
342 print "Project %s already exists, checking project status" % (sample_project)
343 check_project_not_running(lc, sample_project, kill=sample_overkill)
344 check_project_not_recording(lc, sample_project, kill=sample_overkill)
346 print "Project %s does not exists, creating..." % (sample_project)
347 lc.project_create(sample_project)
349 print "Saving to project %s" % (sample_project)
355 if sample_binary
and not sample_binary
in sample_input_files:
356 print "Adding binary %s to files being uploaded" % (sample_binary)
357 sample_input_files.append(sample_binary)
359 print "Uploading files: %s" % (sample_input_files)
361 for f
in upload_input_files(lc, sample_project, sample_input_files):
362 print "\tUploaded %s" % f
366 print "Recording: %s" % (
"<interactive>" if not sample_binary
else "%s with %s" % (sample_binary, sample_binary_arguments))
368 print "Configuring scenario recording" 370 scenario_config = ScenarioConfigurator(vm_cfg=vm_cfg, binary=sample_binary, args=sample_binary_arguments, dump_hint=
None).validate()
372 print "Start scenario recording" 374 vnc_port = scenario_config.recording.vnc_port
375 vnc_password = scenario_config.recording.vnc_password
377 print "VNC conf %s::%s -p %s" % (lc.hostname, vnc_port, vnc_password)
381 lc.project_record_scenario(sample_project, scenario_config)
383 is_scenario_successful = wait_recording(lc, sample_project)
385 if is_scenario_successful:
386 print "Scenario recorded!" 388 print "Error while recording scenario" 393 client = open_project(lc, sample_project)
395 print "Error while connecting to project" 401 print "Launching execution" 403 client.start_execution()
404 wait_execution(client)
408 axion_launch_command =
"axion --host %s --port %s" % (lc.hostname, port)
409 print axion_launch_command
410 system(axion_launch_command)