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 0a03c2c0ec..10c10972b7 100755 --- a/tools/states_to_dot.py +++ b/tools/states_to_dot.py @@ -67,18 +67,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())