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_generating(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 generation.
124 project_scenario = launcher_connection.project_scenario(project)
129 if project_scenario.is_generating:
131 print "Aborting previous scenario generation"
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_generation_config()
164 self._sc.generation.enable_instruction_tracing =
False
165 self._sc.generation.is_interactive =
True
169 self._set_binary(binary, args, dump_hint)
171 def _set_vm(self, vm_cfg):
173 @param: vm_cfg: VM config to use (reven_api.vm_info)
175 self._sc.generation.vnc_password = vm_cfg.vnc_password
or default_vnc_password
176 self._sc.generation.vnc_port = vm_cfg.vnc_port
or default_vnc_port
178 self._sc.scenario.vm_config_name = vm_cfg.name
179 self._sc.scenario.system_pdb_path = vm_cfg.pdb_path
181 def _set_binary(self, binary, args=[], dump_hint=None):
182 self._sc.generation.is_interactive =
False
184 self._sc.scenario.binary_name = basename(binary)
if binary
else ''
185 self._sc.scenario.binary_arguments =
' '.join(args)
186 self._sc.scenario.binary_dump_hint = dump_hint
or ''
187 self._sc.scenario.binary_dump_address = dump_hint
or ''
191 @return: Scenario configuration (reven_api.scenario_generation_config)
195 def stop_recording(vnc_host, vnc_port, vnc_password):
197 Gracefully stop scenario recording using VNC to send magic key sequence 'F9', 'F7'.
198 @param vnc_host: hostname to connect to.
199 @param vnc_port: port to connect to.
200 @param vnc_password: password to use.
202 from vncdotool
import api
as vnc
204 vnc.connect(
'%s::%s' % (vnc_host, vnc_port), vnc_password).keyDown(
'f9').keyDown(
'f7')
208 def abort_recording(launcher_connection, project):
210 Abort scenario recording for given project (will discard currently recorded data).
211 @param launcher_connection: launcher handle (reven_api.launcher_connection)
212 @param project: project to abort recording for (reven_api.project_id)
214 launcher_connection.project_abort_scenario_generation(project)
216 def watch_recording(launcher_connection, project):
218 @param launcher_connection: launcher handle (reven_api.launcher_connection)
219 @param project: project to watch recording (reven_api.project_id)
220 @return: yield recording progress (reven_api.scenario_generation_info)
224 progress = launcher_connection.project_scenario(project)
225 recording = progress.is_generating
229 def wait_recording(launcher_connection, project, soft_timeout=10, hard_timeout=30):
231 Blocks until scenario is recorded or stopped.
232 @param launcher_connection: launcher handle (reven_api.launcher_connection)
233 @param project: project to wait recording (reven_api.project_id)
234 @param soft_timeout: Timeout in seconds before trying to stop scenario recording
235 @param hard_timeout: Timeout in seconds before trying to abort scenario recording (recorded data are discarded)
237 for i, progress
in enumerate(watch_recording(launcher_connection, project)):
238 if progress.log_chunk:
239 print progress.log_chunk
241 if i == soft_timeout:
242 print "Soft timeout: stopping scenario recording"
244 stop_recording(launcher_connection.hostname, vnc_port, vnc_password)
245 except Exception
as e:
246 print "Could not gracefully stop recording through vnc (%s)" % e
247 elif i == hard_timeout:
248 print "Hard timeout: aborting scenario recording"
249 abort_recording(launcher_connection, project)
253 return progress.is_successful
257 def open_project(launcher_connection, project):
259 Open project (launch a server)
260 @param launcher_connection: launcher handle (reven_api.launcher_connection)
261 @param project: project to open (reven_api.project_id)
262 @return: handle to project (reven.Project)
265 port = launcher_connection.server_launch(project)
267 print "Error server not started for project %s" % project
269 print "Server started on port %s" % port
276 client = reven.Project(launcher_connection.hostname, port)
279 except RuntimeError
as e:
280 print "Could not connect (%s)" % e
286 def wait_execution(reven_client):
288 Block until execution is completed.
289 @param reven_client: opened project handle (reven.Project)
292 progress = reven_client.execution_status()
294 print "# %s/%s - %s/%s - %s" % (
295 progress.tsc, progress.last_tsc,
296 progress.point_index, progress.last_point_index,
299 if not progress.is_busy:
305 if __name__ ==
'__main__':
310 launcher_hostname = args.host
311 launcher_port = args.port
312 sample_project = reven_api.project_id(args.user, args.project)
313 sample_binary = args.binary
314 sample_binary_arguments = args.args
315 sample_input_files = args.files
317 sample_overkill = args.kill
319 sample_is_interactive =
not sample_binary
323 print "Connecting to %s:%s" % (launcher_hostname, launcher_port)
325 lc = connect_to_launcher(launcher_hostname, launcher_port)
329 vm_cfg = vm_config_by_name(lc, sample_vm)
331 print "Vm config %s not found." % (sample_vm)
332 print_available_vms(lc)
335 print "Using vm config %s: %s" % (sample_vm, vm_cfg.display)
339 if not user_exists(lc, sample_project.user):
340 print "User %s does not exist (will be created)" % sample_project.user
342 if project_exists(lc, sample_project):
343 print "Project %s already exists, checking project status" % (sample_project)
344 check_project_not_running(lc, sample_project, kill=sample_overkill)
345 check_project_not_generating(lc, sample_project, kill=sample_overkill)
347 print "Project %s does not exists, creating..." % (sample_project)
348 lc.project_create(sample_project)
350 print "Saving to project %s" % (sample_project)
356 if sample_binary
and not sample_binary
in sample_input_files:
357 print "Adding binary %s to files being uploaded" % (sample_binary)
358 sample_input_files.append(sample_binary)
360 print "Uploading files: %s" % (sample_input_files)
362 for f
in upload_input_files(lc, sample_project, sample_input_files):
363 print "\tUploaded %s" % f
367 print "Recording: %s" % (
"<interactive>" if not sample_binary
else "%s with %s" % (sample_binary, sample_binary_arguments))
369 print "Configuring scenario recording"
371 scenario_config = ScenarioConfigurator(vm_cfg=vm_cfg, binary=sample_binary, args=sample_binary_arguments, dump_hint=
None).validate()
373 print "Start scenario recording"
375 vnc_port = scenario_config.generation.vnc_port
376 vnc_password = scenario_config.generation.vnc_password
378 print "VNC conf %s::%s -p %s" % (lc.hostname, vnc_port, vnc_password)
382 lc.project_generate_scenario(sample_project, scenario_config)
384 is_scenario_successful = wait_recording(lc, sample_project)
386 if is_scenario_successful:
387 print "Scenario recorded!"
389 print "Error while recording scenario"
394 client = open_project(lc, sample_project)
396 print "Error while connecting to project"
402 print "Launching execution"
404 client.start_execution()
405 wait_execution(client)
409 axion_launch_command =
"axion --host %s --port %s" % (lc.hostname, port)
410 print axion_launch_command
411 system(axion_launch_command)