Add fsm dot diagram generator
Add a tool which generates dot diagram from inspector state machine using atomaton pydot convertor. Also add generated svg diagram to docs. Change-Id: I021812288f1833a6ebad2f90cbe862d40bd8d503
This commit is contained in:
parent
d2bbf3ec96
commit
886d05ee64
174
doc/source/images/states.svg
Normal file
174
doc/source/images/states.svg
Normal file
@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.36.0 (20140111.2315)
|
||||
-->
|
||||
<!-- Title: Ironic Inspector states Pages: 1 -->
|
||||
<svg width="832pt" height="318pt"
|
||||
viewBox="0.00 0.00 832.00 318.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 314)">
|
||||
<title>Ironic Inspector states</title>
|
||||
<polygon fill="white" stroke="none" points="-4,4 -4,-314 828,-314 828,4 -4,4"/>
|
||||
<!-- enrolling -->
|
||||
<g id="node1" class="node"><title>enrolling</title>
|
||||
<ellipse fill="none" stroke="black" cx="34" cy="-251" rx="33.8507" ry="18"/>
|
||||
<text text-anchor="middle" x="34" y="-248.2" font-family="Times,serif" font-size="11.00" fill="gray">enrolling</text>
|
||||
</g>
|
||||
<!-- error -->
|
||||
<g id="node2" class="node"><title>error</title>
|
||||
<ellipse fill="none" stroke="black" cx="151" cy="-150" rx="27" ry="18"/>
|
||||
<text text-anchor="middle" x="151" y="-147.2" font-family="Times,serif" font-size="11.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- enrolling->error -->
|
||||
<g id="edge1" class="edge"><title>enrolling->error</title>
|
||||
<path fill="none" stroke="black" d="M52.466,-235.66C72.1644,-218.36 104.307,-190.13 126.269,-170.842"/>
|
||||
<polygon fill="black" stroke="black" points="128.654,-173.405 133.858,-164.177 124.035,-168.146 128.654,-173.405"/>
|
||||
<text text-anchor="middle" x="96" y="-206" font-family="Times,serif" font-size="10.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- processing -->
|
||||
<g id="node3" class="node"><title>processing</title>
|
||||
<ellipse fill="none" stroke="black" cx="517" cy="-150" rx="38.4712" ry="18"/>
|
||||
<text text-anchor="middle" x="517" y="-147.2" font-family="Times,serif" font-size="11.00" fill="gray">processing</text>
|
||||
</g>
|
||||
<!-- enrolling->processing -->
|
||||
<g id="edge2" class="edge"><title>enrolling->processing</title>
|
||||
<path fill="none" stroke="black" d="M55.1347,-265.142C77.3021,-279.301 114.519,-299 150,-299 150,-299 150,-299 381,-299 418.718,-299 432.423,-293.732 460,-268 486.199,-243.553 501.392,-204.325 509.183,-177.88"/>
|
||||
<polygon fill="black" stroke="black" points="512.599,-178.66 511.903,-168.088 505.854,-176.787 512.599,-178.66"/>
|
||||
<text text-anchor="middle" x="264" y="-302" font-family="Times,serif" font-size="10.00">process</text>
|
||||
</g>
|
||||
<!-- error->error -->
|
||||
<g id="edge3" class="edge"><title>error->error</title>
|
||||
<path fill="none" stroke="black" d="M146.146,-167.782C145.322,-177.315 146.939,-186 151,-186 153.474,-186 155.042,-182.775 155.702,-178.098"/>
|
||||
<polygon fill="black" stroke="black" points="159.206,-177.832 155.854,-167.782 152.207,-177.729 159.206,-177.832"/>
|
||||
<text text-anchor="middle" x="151" y="-189" font-family="Times,serif" font-size="10.00" fill="red">abort</text>
|
||||
</g>
|
||||
<!-- error->error -->
|
||||
<g id="edge6" class="edge"><title>error->error</title>
|
||||
<path fill="none" stroke="black" d="M143.026,-167.42C138.481,-184.791 141.139,-204 151,-204 158.935,-204 162.206,-191.562 160.813,-177.652"/>
|
||||
<polygon fill="black" stroke="black" points="164.188,-176.643 158.974,-167.42 157.298,-177.882 164.188,-176.643"/>
|
||||
<text text-anchor="middle" x="151" y="-207" font-family="Times,serif" font-size="10.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- starting -->
|
||||
<g id="node4" class="node"><title>starting</title>
|
||||
<ellipse fill="none" stroke="black" cx="264" cy="-140" rx="30.1339" ry="18"/>
|
||||
<text text-anchor="middle" x="264" y="-137.2" font-family="Times,serif" font-size="11.00" fill="gray">starting</text>
|
||||
</g>
|
||||
<!-- error->starting -->
|
||||
<g id="edge4" class="edge"><title>error->starting</title>
|
||||
<path fill="none" stroke="black" d="M177.86,-148.145C189.52,-147.266 203.459,-146.157 216,-145 218.666,-144.754 221.416,-144.49 224.184,-144.215"/>
|
||||
<polygon fill="black" stroke="black" points="224.587,-147.693 234.18,-143.195 223.876,-140.729 224.587,-147.693"/>
|
||||
<text text-anchor="middle" x="206" y="-149" font-family="Times,serif" font-size="10.00">start</text>
|
||||
</g>
|
||||
<!-- reapplying -->
|
||||
<g id="node5" class="node"><title>reapplying</title>
|
||||
<ellipse fill="none" stroke="black" cx="786" cy="-27" rx="37.7689" ry="18"/>
|
||||
<text text-anchor="middle" x="786" y="-24.2" font-family="Times,serif" font-size="11.00" fill="gray">reapplying</text>
|
||||
</g>
|
||||
<!-- error->reapplying -->
|
||||
<g id="edge5" class="edge"><title>error->reapplying</title>
|
||||
<path fill="none" stroke="black" d="M160.369,-167.008C176.101,-196.263 213.05,-253 263,-253 263,-253 263,-253 649,-253 740.366,-253 771.925,-115.721 781.403,-55.1474"/>
|
||||
<polygon fill="black" stroke="black" points="784.887,-55.5155 782.88,-45.1125 777.961,-54.4964 784.887,-55.5155"/>
|
||||
<text text-anchor="middle" x="444" y="-256" font-family="Times,serif" font-size="10.00">reapply</text>
|
||||
</g>
|
||||
<!-- processing->error -->
|
||||
<g id="edge10" class="edge"><title>processing->error</title>
|
||||
<path fill="none" stroke="black" d="M488.02,-162.185C436.942,-182.754 325.428,-219.893 234,-196 213.801,-190.721 193.318,-179.235 177.876,-169.062"/>
|
||||
<polygon fill="black" stroke="black" points="179.639,-166.028 169.406,-163.281 175.692,-171.81 179.639,-166.028"/>
|
||||
<text text-anchor="middle" x="322" y="-206" font-family="Times,serif" font-size="10.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- finished -->
|
||||
<g id="node6" class="node"><title>finished</title>
|
||||
<ellipse fill="none" stroke="black" cx="648" cy="-77" rx="31.0408" ry="18"/>
|
||||
<text text-anchor="middle" x="648" y="-74.2" font-family="Times,serif" font-size="11.00" fill="gray">finished</text>
|
||||
</g>
|
||||
<!-- processing->finished -->
|
||||
<g id="edge11" class="edge"><title>processing->finished</title>
|
||||
<path fill="none" stroke="black" d="M542.264,-136.269C563.176,-124.435 593.483,-107.285 616.12,-94.4746"/>
|
||||
<polygon fill="black" stroke="black" points="618.016,-97.4231 624.996,-89.452 614.569,-91.3309 618.016,-97.4231"/>
|
||||
<text text-anchor="middle" x="586" y="-120" font-family="Times,serif" font-size="10.00">finish</text>
|
||||
</g>
|
||||
<!-- starting->error -->
|
||||
<g id="edge15" class="edge"><title>starting->error</title>
|
||||
<path fill="none" stroke="black" d="M236.121,-132.968C223.823,-130.728 209.104,-129.423 196,-132 191.505,-132.884 186.892,-134.23 182.422,-135.798"/>
|
||||
<polygon fill="black" stroke="black" points="181.011,-132.591 172.968,-139.487 183.556,-139.112 181.011,-132.591"/>
|
||||
<text text-anchor="middle" x="206" y="-135" font-family="Times,serif" font-size="10.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- starting->starting -->
|
||||
<g id="edge17" class="edge"><title>starting->starting</title>
|
||||
<path fill="none" stroke="black" d="M253.722,-157.037C251.625,-166.858 255.051,-176 264,-176 269.593,-176 273.029,-172.429 274.307,-167.353"/>
|
||||
<polygon fill="black" stroke="black" points="277.806,-167.027 274.278,-157.037 270.806,-167.047 277.806,-167.027"/>
|
||||
<text text-anchor="middle" x="264" y="-179" font-family="Times,serif" font-size="10.00">start</text>
|
||||
</g>
|
||||
<!-- waiting -->
|
||||
<g id="node7" class="node"><title>waiting</title>
|
||||
<ellipse fill="none" stroke="black" cx="380" cy="-93" rx="30.1339" ry="18"/>
|
||||
<text text-anchor="middle" x="380" y="-90.2" font-family="Times,serif" font-size="11.00" fill="gray">waiting</text>
|
||||
</g>
|
||||
<!-- starting->waiting -->
|
||||
<g id="edge16" class="edge"><title>starting->waiting</title>
|
||||
<path fill="none" stroke="black" d="M289.176,-130.033C305.5,-123.303 327.271,-114.327 345.291,-106.897"/>
|
||||
<polygon fill="black" stroke="black" points="346.947,-110.001 354.858,-102.953 344.279,-103.529 346.947,-110.001"/>
|
||||
<text text-anchor="middle" x="322" y="-122" font-family="Times,serif" font-size="10.00">wait</text>
|
||||
</g>
|
||||
<!-- reapplying->error -->
|
||||
<g id="edge12" class="edge"><title>reapplying->error</title>
|
||||
<path fill="none" stroke="black" d="M754.017,-17.2524C726.674,-9.51855 685.589,-0 649,-0 263,-0 263,-0 263,-0 202.716,-0 171.423,-79.2538 158.826,-122.545"/>
|
||||
<polygon fill="black" stroke="black" points="155.447,-121.633 156.152,-132.204 162.194,-123.501 155.447,-121.633"/>
|
||||
<text text-anchor="middle" x="444" y="-3" font-family="Times,serif" font-size="10.00" fill="red">error</text>
|
||||
</g>
|
||||
<!-- reapplying->reapplying -->
|
||||
<g id="edge13" class="edge"><title>reapplying->reapplying</title>
|
||||
<path fill="none" stroke="black" d="M773.242,-44.0373C770.638,-53.8579 774.891,-63 786,-63 792.943,-63 797.208,-59.4289 798.795,-54.3529"/>
|
||||
<polygon fill="black" stroke="black" points="802.294,-54.0248 798.758,-44.0373 795.294,-54.0497 802.294,-54.0248"/>
|
||||
<text text-anchor="middle" x="786" y="-66" font-family="Times,serif" font-size="10.00">reapply</text>
|
||||
</g>
|
||||
<!-- reapplying->finished -->
|
||||
<g id="edge14" class="edge"><title>reapplying->finished</title>
|
||||
<path fill="none" stroke="black" d="M748.627,-23.7035C732.542,-23.5857 713.745,-25.3404 698,-32 686.924,-36.6849 676.751,-45.0033 668.58,-53.2245"/>
|
||||
<polygon fill="black" stroke="black" points="665.926,-50.9381 661.67,-60.6402 671.048,-55.7102 665.926,-50.9381"/>
|
||||
<text text-anchor="middle" x="714" y="-35" font-family="Times,serif" font-size="10.00">finish</text>
|
||||
</g>
|
||||
<!-- finished->starting -->
|
||||
<g id="edge7" class="edge"><title>finished->starting</title>
|
||||
<path fill="none" stroke="black" d="M636.838,-94.1322C622.158,-117.186 592.709,-157.541 556,-177 507.861,-202.518 360.889,-225.049 312,-201 297.23,-193.735 285.796,-179.349 277.906,-166.372"/>
|
||||
<polygon fill="black" stroke="black" points="280.748,-164.287 272.789,-157.293 274.65,-167.724 280.748,-164.287"/>
|
||||
<text text-anchor="middle" x="444" y="-211" font-family="Times,serif" font-size="10.00">start</text>
|
||||
</g>
|
||||
<!-- finished->reapplying -->
|
||||
<g id="edge8" class="edge"><title>finished->reapplying</title>
|
||||
<path fill="none" stroke="black" d="M674.901,-67.4777C694.996,-60.0896 723.179,-49.7282 746,-41.3383"/>
|
||||
<polygon fill="black" stroke="black" points="747.235,-44.6134 755.413,-37.8777 744.819,-38.0434 747.235,-44.6134"/>
|
||||
<text text-anchor="middle" x="714" y="-60" font-family="Times,serif" font-size="10.00">reapply</text>
|
||||
</g>
|
||||
<!-- finished->finished -->
|
||||
<g id="edge9" class="edge"><title>finished->finished</title>
|
||||
<path fill="none" stroke="black" d="M637.014,-94.0373C634.771,-103.858 638.434,-113 648,-113 653.979,-113 657.652,-109.429 659.018,-104.353"/>
|
||||
<polygon fill="black" stroke="black" points="662.517,-104.027 658.986,-94.0373 655.517,-104.048 662.517,-104.027"/>
|
||||
<text text-anchor="middle" x="648" y="-116" font-family="Times,serif" font-size="10.00">finish</text>
|
||||
</g>
|
||||
<!-- waiting->error -->
|
||||
<g id="edge18" class="edge"><title>waiting->error</title>
|
||||
<path fill="none" stroke="black" d="M349.964,-90.9081C320.18,-89.6551 272.844,-90.1631 234,-102 213.818,-108.15 193.335,-120.136 177.889,-130.591"/>
|
||||
<polygon fill="black" stroke="black" points="175.606,-127.916 169.416,-136.515 179.617,-133.653 175.606,-127.916"/>
|
||||
<text text-anchor="middle" x="264" y="-105" font-family="Times,serif" font-size="10.00" fill="red">timeout</text>
|
||||
</g>
|
||||
<!-- waiting->error -->
|
||||
<g id="edge19" class="edge"><title>waiting->error</title>
|
||||
<path fill="none" stroke="black" d="M354.203,-83.6922C324.773,-74.0865 274.58,-62.2845 234,-76 207.376,-84.9985 184.362,-107.946 169.549,-125.923"/>
|
||||
<polygon fill="black" stroke="black" points="166.803,-123.753 163.337,-133.765 172.29,-128.099 166.803,-123.753"/>
|
||||
<text text-anchor="middle" x="264" y="-79" font-family="Times,serif" font-size="10.00" fill="red">abort</text>
|
||||
</g>
|
||||
<!-- waiting->processing -->
|
||||
<g id="edge20" class="edge"><title>waiting->processing</title>
|
||||
<path fill="none" stroke="black" d="M405.135,-103.19C425.532,-111.803 455.091,-124.283 478.559,-134.191"/>
|
||||
<polygon fill="black" stroke="black" points="477.298,-137.458 487.872,-138.124 480.021,-131.009 477.298,-137.458"/>
|
||||
<text text-anchor="middle" x="444" y="-127" font-family="Times,serif" font-size="10.00">process</text>
|
||||
</g>
|
||||
<!-- waiting->starting -->
|
||||
<g id="edge21" class="edge"><title>waiting->starting</title>
|
||||
<path fill="none" stroke="black" d="M350.002,-91.1267C337.839,-91.3523 323.808,-92.9812 312,-98 302.03,-102.238 292.742,-109.479 285.1,-116.767"/>
|
||||
<polygon fill="black" stroke="black" points="282.547,-114.371 278.042,-123.961 287.543,-119.274 282.547,-114.371"/>
|
||||
<text text-anchor="middle" x="322" y="-101" font-family="Times,serif" font-size="10.00">start</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
@ -56,6 +56,17 @@ Usual hardware introspection flow is as follows:
|
||||
Starting DHCP server and configuring PXE boot environment is not part of this
|
||||
package and should be done separately.
|
||||
|
||||
State machine diagram
|
||||
=====================
|
||||
|
||||
The diagram below shows the introspection states that an **ironic-inspector**
|
||||
FSM goes through during the node introspection, discovery and reprocessing.
|
||||
The diagram also shows events that trigger state transitions.
|
||||
|
||||
.. figure:: ./images/states.svg
|
||||
:width: 660px
|
||||
:align: center
|
||||
:alt: ironic-inspector state machine diagram
|
||||
|
||||
.. _Ironic inspection documentation: http://docs.openstack.org/developer/ironic/deploy/install-guide.html#hardware-inspection
|
||||
.. _Ironic: https://wiki.openstack.org/wiki/Ironic
|
||||
|
||||
|
94
tools/states_to_dot.py
Executable file
94
tools/states_to_dot.py
Executable file
@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env python
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import optparse
|
||||
|
||||
from automaton.converters import pydot
|
||||
|
||||
from ironic_inspector import introspection_state as states
|
||||
|
||||
|
||||
def print_header(text):
|
||||
print("*" * len(text))
|
||||
print(text)
|
||||
print("*" * len(text))
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
5
tox.ini
5
tox.ini
@ -45,6 +45,11 @@ commands =
|
||||
envdir = {toxworkdir}/venv
|
||||
commands = oslo-config-generator --config-file config-generator.conf
|
||||
|
||||
[testenv:genstates]
|
||||
deps = {[testenv]deps}
|
||||
pydot2
|
||||
commands = {toxinidir}/tools/states_to_dot.py -f {toxinidir}/doc/source/images/states.svg --format svg
|
||||
|
||||
[flake8]
|
||||
max-complexity=15
|
||||
# [H106] Don’t put vim configuration in source files.
|
||||
|
Loading…
Reference in New Issue
Block a user