def main(): parser = optparse.OptionParser() parser.add_option("-f", "--file", dest="filename", help="write output to FILE", metavar="FILE") parser.add_option("-T", "--format", dest="format", help="output in given format (default: png)", default='png') parser.add_option("--no-labels", dest="labels", help="do not include labels", action='store_false', default=True) (options, args) = parser.parse_args() if options.filename is None: options.filename = 'states.%s' % options.format def edge_attrs(start_state, event, end_state): attrs = {} if options.labels: attrs['label'] = "on_%s" % event attrs.update(map_color(event)) return attrs source = states.machine graph_name = '"Ironic states"' graph_attrs = {'size': 0} g = pydot.convert(source, graph_name, graph_attrs=graph_attrs, node_attrs_cb=map_color, edge_attrs_cb=edge_attrs) print_header(graph_name) print(g.to_string().strip()) g.write(options.filename, format=options.format) print_header("Created %s at '%s'" % (options.format, options.filename))
def main(): parser = optparse.OptionParser() parser.add_option("-f", "--file", dest="filename", help="write output to FILE", metavar="FILE") parser.add_option("-T", "--format", dest="format", help="output in given format (default: png)", default='png') parser.add_option("--no-labels", dest="labels", help="do not include labels", action='store_false', default=True) (options, args) = parser.parse_args() if options.filename is None: options.filename = 'states.%s' % options.format def node_attrs(state): """Attributes used for drawing the nodes (states). The user can perform actions on introspection states, we distinguish the error states from the other states by highlighting the node. Error stable states are labelled with red. This is a callback method used by pydot.convert(). :param state: name of state :returns: A dictionary with graphic attributes used for displaying the state. # """ attrs = {} attrs['fontcolor'] = 'red' if 'error' in state else 'gray' return attrs def edge_attrs(start_state, event, end_state): """Attributes used for drawing the edges (transitions). This is a callback method used by pydot.convert(). :param start_state: name of the start state :param event: the event, a string :param end_state: name of the end state (unused) :returns: A dictionary with graphic attributes used for displaying the transition. """ if not options.labels: return {} attrs = {} attrs['fontsize'] = 10 attrs['label'] = event if end_state is 'error': attrs['fontcolor'] = 'red' return attrs source = states.FSM graph_name = '"Ironic Inspector states"' graph_attrs = {'size': 0} dot_graph = pydot.convert( source, graph_name, graph_attrs=graph_attrs, node_attrs_cb=node_attrs, edge_attrs_cb=edge_attrs, add_start_state=False) dot_graph.write(options.filename, format=options.format) print(dot_graph.to_string()) print_header("Created %s at '%s'" % (options.format, options.filename))
def main(): parser = optparse.OptionParser() parser.add_option("-f", "--file", dest="filename", help="write svg to FILE", metavar="FILE") parser.add_option("-t", "--tasks", dest="tasks", action='store_true', help="use task state transitions", default=False) parser.add_option("-r", "--retries", dest="retries", action='store_true', help="use retry state transitions", default=False) parser.add_option("-e", "--engines", dest="engines", action='store_true', help="use engine state transitions", default=False) parser.add_option("-w", "--wbe-requests", dest="wbe_requests", action='store_true', help="use wbe request transitions", default=False) parser.add_option("-j", "--jobs", dest="jobs", action='store_true', help="use job transitions", default=False) parser.add_option("--flow", dest="flow", action='store_true', help="use flow transitions", default=False) parser.add_option("-T", "--format", dest="format", help="output in given format", default='svg') (options, args) = parser.parse_args() if options.filename is None: options.filename = 'states.%s' % options.format types = [ options.engines, options.retries, options.tasks, options.wbe_requests, options.jobs, options.flow, ] provided = sum([int(i) for i in types]) if provided > 1: parser.error("Only one of task/retry/engines/wbe requests/jobs/flow" " may be specified.") if provided == 0: parser.error("One of task/retry/engines/wbe requests/jobs/flow" " must be specified.") event_name_cb = lambda start_state, end_state: "on_%s" % end_state.lower() internal_states = list() ordering = 'in' if options.tasks: source_type = "Tasks" source = make_machine(states.PENDING, list(states._ALLOWED_TASK_TRANSITIONS), event_name_cb) elif options.retries: source_type = "Retries" source = make_machine(states.PENDING, list(states._ALLOWED_RETRY_TRANSITIONS), event_name_cb) elif options.flow: source_type = "Flow" source = make_machine(states.PENDING, list(states._ALLOWED_FLOW_TRANSITIONS), event_name_cb) elif options.engines: source_type = "Engines" b = builder.MachineBuilder(DummyRuntime(), mock.MagicMock()) source, memory = b.build() internal_states.extend(builder.META_STATES) ordering = 'out' elif options.wbe_requests: source_type = "WBE requests" source = make_machine(protocol.WAITING, list(protocol._ALLOWED_TRANSITIONS), event_name_cb) elif options.jobs: source_type = "Jobs" source = make_machine(states.UNCLAIMED, list(states._ALLOWED_JOB_TRANSITIONS), event_name_cb) graph_attrs = { 'ordering': ordering, } graph_name = "%s states" % source_type def node_attrs_cb(state): node_color = None if state in internal_states: node_color = 'blue' if state in (states.FAILURE, states.REVERT_FAILURE): node_color = 'red' if state == states.REVERTED: node_color = 'darkorange' if state in (states.SUCCESS, states.COMPLETE): node_color = 'green' node_attrs = {} if node_color: node_attrs['fontcolor'] = node_color return node_attrs def edge_attrs_cb(start_state, on_event, end_state): edge_attrs = {} if options.engines: edge_attrs['label'] = on_event.replace("_", " ").strip() if 'reverted' in on_event: edge_attrs['fontcolor'] = 'darkorange' if 'fail' in on_event: edge_attrs['fontcolor'] = 'red' if 'success' in on_event: edge_attrs['fontcolor'] = 'green' return edge_attrs g = pydot.convert(source, graph_name, graph_attrs=graph_attrs, node_attrs_cb=node_attrs_cb, edge_attrs_cb=edge_attrs_cb) print("*" * len(graph_name)) print(graph_name) print("*" * len(graph_name)) print(source.pformat()) print(g.to_string().strip()) g.write(options.filename, format=options.format) print("Created %s at '%s'" % (options.format, options.filename))
def main(): parser = optparse.OptionParser() parser.add_option("-f", "--file", dest="filename", help="write output to FILE", metavar="FILE") parser.add_option("-T", "--format", dest="format", help="output in given format (default: png)", default='png') parser.add_option("--no-labels", dest="labels", help="do not include labels", action='store_false', default=True) (options, args) = parser.parse_args() if options.filename is None: options.filename = 'states.%s' % options.format def node_attrs(state): """Attributes used for drawing the nodes (states). The user can perform actions on stable states (and in a few other cases), so we distinguish the stable states from the other states by highlighting the node. Non-stable states are labelled with gray. This is a callback method used by pydot.convert(). :param state: name of state :returns: A dictionary with graphic attributes used for displaying the state. """ attrs = map_color(state) if source.is_stable(state): attrs['penwidth'] = 1.7 else: if 'fontcolor' not in attrs: attrs['fontcolor'] = 'gray' return attrs def edge_attrs(start_state, event, end_state): """Attributes used for drawing the edges (transitions). There are two types of transitions; the ones that the user can initiate and the ones that are done internally by the conductor. The user-initiated ones are shown with '(via API'); the others are in gray. This is a callback method used by pydot.convert(). :param start_state: name of the start state :param event: the event, a string :param end_state: name of the end state (unused) :returns: A dictionary with graphic attributes used for displaying the transition. """ if not options.labels: return {} translations = {'delete': 'deleted', 'deploy': 'active'} attrs = {} attrs['fontsize'] = 12 attrs['label'] = translations.get(event, event) if (source.is_stable(start_state) or 'fail' in start_state or event in ('abort', 'delete')): attrs['label'] += " (via API)" else: attrs['fontcolor'] = 'gray' return attrs source = states.machine graph_name = '"Ironic states"' graph_attrs = {'size': 0} g = pydot.convert(source, graph_name, graph_attrs=graph_attrs, node_attrs_cb=node_attrs, edge_attrs_cb=edge_attrs) print_header(graph_name) print(g.to_string().strip()) g.write(options.filename, format=options.format) print_header("Created %s at '%s'" % (options.format, options.filename))