From 4f8b97dff68dcdea02f769de8d0721e8e98fa029 Mon Sep 17 00:00:00 2001 From: Ruby Loo Date: Thu, 17 Dec 2015 16:25:56 +0000 Subject: [PATCH] Show transitions initiated by API requests This updates the state machine diagram and documentation to indicate which transitions are initiated by API requests versus the ones that are internally done by the conductor. Stable states are highlighted a bit. Change-Id: I1a2de81b14696286f1da47c06374ad235962c849 Closes-Bug: #1527316 --- doc/source/dev/states.rst | 8 +- doc/source/images/states.svg | 278 +++++++++++++++++------------------ tools/states_to_dot.py | 52 ++++++- 3 files changed, 194 insertions(+), 144 deletions(-) diff --git a/doc/source/dev/states.rst b/doc/source/dev/states.rst index 9ebe6951d9..185bf2fc83 100644 --- a/doc/source/dev/states.rst +++ b/doc/source/dev/states.rst @@ -11,6 +11,12 @@ The diagram below shows the provisioning states that an Ironic node goes through during the lifetime of a node. The diagram also depicts the events that transition the node to different states. +Stable states are highlighted with a thicker border. All transitions from +stable states are initiated by API requests. There are a few other +API-initiated-transitions that are possible from non-stable states. +The events for these API-initiated transitions are indicated with '(via API)'. +Internally, the conductor initiates the other transitions (depicted in gray). + .. figure:: ../images/states.svg :width: 660px :align: left @@ -21,4 +27,4 @@ that transition the node to different states. For more information about the states, see the specification located at `ironic-state-machine`_. -.. _ironic-state-machine: http://specs.openstack.org/openstack/ironic-specs/specs/kilo/new-ironic-state-machine.html +.. _ironic-state-machine: http://specs.openstack.org/openstack/ironic-specs/specs/kilo-implemented/new-ironic-state-machine.html diff --git a/doc/source/images/states.svg b/doc/source/images/states.svg index 775792e318..587892f28b 100644 --- a/doc/source/images/states.svg +++ b/doc/source/images/states.svg @@ -4,295 +4,295 @@ - - + + Ironic states - + enroll - -enroll + +enroll verifying - -verifying + +verifying enroll->verifying - - -on_manage + + +manage (via API) manageable - -manageable + +manageable verifying->manageable - - -on_done + + +done verifying->enroll - - -on_fail + + +fail cleaning - -cleaning + +cleaning manageable->cleaning - - -on_provide + + +provide (via API) manageable->cleaning - - -on_clean + + +clean (via API) inspecting - -inspecting + +inspecting manageable->inspecting - - -on_inspect + + +inspect (via API) available - -available + +available cleaning->available - - -on_done + + +done clean failed - -clean failed + +clean failed cleaning->clean failed - - -on_fail + + +fail clean wait - -clean wait + +clean wait cleaning->clean wait - - -on_wait + + +wait cleaning->manageable - - -on_manage + + +manage inspecting->manageable - - -on_done + + +done inspect failed - -inspect failed + +inspect failed inspecting->inspect failed - - -on_fail + + +fail deploying - -deploying + +deploying available->deploying - - -on_deploy + + +active (via API) available->manageable - - -on_manage + + +manage (via API) deploy failed - -deploy failed + +deploy failed deploying->deploy failed - - -on_fail + + +fail wait call-back - -wait call-back + +wait call-back deploying->wait call-back - - -on_wait + + +wait active - -active + +active deploying->active - - -on_done + + +done active->deploying - - -on_rebuild + + +rebuild (via API) deleting - -deleting + +deleting active->deleting - - -on_delete + + +deleted (via API) error - -error + +error deleting->error - - -on_error + + +error deleting->cleaning - - -on_clean + + +clean error->deploying - - -on_rebuild + + +rebuild (via API) error->deleting - - -on_delete + + +deleted (via API) deploy failed->deploying - - -on_rebuild + + +rebuild (via API) deploy failed->deploying - - -on_deploy + + +active (via API) deploy failed->deleting - - -on_delete + + +deleted (via API) wait call-back->deploying - - -on_resume + + +resume wait call-back->deploy failed - - -on_fail + + +fail wait call-back->deleting - - -on_delete + + +deleted (via API) clean failed->manageable - - -on_manage + + +manage (via API) clean wait->clean failed - - -on_fail + + +fail clean wait->clean failed - - -on_abort + + +abort (via API) clean wait->cleaning - - -on_resume + + +resume inspect failed->manageable - - -on_manage + + +manage (via API) inspect failed->inspecting - - -on_inspect + + +inspect (via API) diff --git a/tools/states_to_dot.py b/tools/states_to_dot.py index c452351c20..16b4365719 100755 --- a/tools/states_to_dot.py +++ b/tools/states_to_dot.py @@ -66,18 +66,62 @@ def main(): 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 = {} - if options.labels: - attrs['label'] = "on_%s" % event - attrs.update(map_color(event)) + 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=map_color, edge_attrs_cb=edge_attrs) + node_attrs_cb=node_attrs, edge_attrs_cb=edge_attrs) print_header(graph_name) print(g.to_string().strip())