github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/doc/lifecycles.txt (about)

     1  Lifecycles
     2  ==========
     3  
     4  In juju, certain fundamental state entities have "lifecycles". These entities
     5  are:
     6  
     7    * Machines
     8    * Units
     9    * Services
    10    * Relations
    11  
    12  ...and there are only 3 possible states for the above things:
    13  
    14    * Alive (An entity is Alive when it is first created.)
    15    * Dying (An entity becomes Dying when the user indicates that it should be
    16      destroyed, and remains so while there are impediments to its removal.)
    17    * Dead (an entity becomes Dead when there are no further impediments to
    18      its removal; at this point it may be removed from the database at any time.
    19      Some entities may become Dead and are removed as a single operation, and
    20      are hence never directly observed to be "Dead", but should still be so
    21      considered.)
    22  
    23  There are two fundamental truths in this system:
    24  
    25    * All such things start existence Alive.
    26    * No such thing can ever change to an earlier state.
    27  
    28  Beyond the above rules, lifecycle shifts occur at different times for different
    29  kinds of entities.
    30  
    31  Machines
    32  --------
    33  
    34    * Like everything else, a machine starts out Alive. `juju bootstrap` aside,
    35      the user interface does not allow for direct creation of machines, but
    36      `juju deploy` and `juju add-unit` may create machines as a consequence of
    37      unit creation.
    38    * If a machine has the JobManageEnviron job, it cannot become Dying or Dead.
    39      Other jobs do not affect the lifecycle directly.
    40    * If a machine has the JobHostUnits job, principal units can be assigned to it
    41      while it is Alive.
    42    * While principal units are assigned to a machine, its lifecycle cannot change
    43      and `juju destroy-machine` will fail.
    44    * When no principal units are assigned, `juju destroy-machine` will set the
    45      machine to Dying. (Future plans: allow a machine to become Dying when it
    46      has principal units, so long as they are not Alive. For now it's extra
    47      complexity with little direct benefit.)
    48    * Once a machine has been set to Dying, the corresponding Machine Agent (MA)
    49      is responsible for setting it to Dead. (Future plans: when Dying units are
    50      assigned, wait for them to become Dead and remove them completely before
    51      making the machine Dead; not an issue now because the machine can't yet
    52      become Dying with units assigned.)
    53    * Once a machine has been set to Dead, the agent for some other machine (with
    54      JobManageEnviron) will release the underlying instance back to the provider
    55      and remove the machine entity from state. (Future uncertainty: should the
    56      provisioner provision an instance for a Dying machine? At the moment, no,
    57      because a Dying machine can't have any units in the first place; in the
    58      future, er, maybe, because those Dying units may be attached to persistent
    59      storage and should thus be allowed to continue to shut down cleanly as they
    60      would usually do. Maybe.)
    61  
    62  Units
    63  -----
    64  
    65    * A principal unit can be created directly with `juju deploy` or
    66      `juju add-unit`.
    67    * While a principal unit is Alive, it can be assigned to a machine.
    68    * While a principal unit is Alive, it can enter the scopes of Alive
    69      relations, which may cause the creation of subordinate units; so,
    70      indirectly, `juju add-relation` can also cause the creation of units.
    71    * A unit can become Dying at any time, but may not become Dead while any unit
    72      subordinate to it exists, or while the unit is in scope for any relation.
    73    * A principal unit can become Dying in one of two ways:
    74        * `juju destroy-unit` (This doesn't work on subordinates; see below.)
    75        * `juju destroy-service` (This does work on subordinates, but happens
    76          indirectly in either case: the Unit Agents (UAs) for each unit of a
    77          service set their corresponding units to Dying when they detect their
    78          service Dying; this is because we try to assume 100k-scale and we can't
    79          use mgo/txn to do a bulk update of 100k units: that makes for a txn
    80          with at least 100k operations, and that's just crazy.)
    81    * A subordinate must also become Dying when either:
    82        * its principal becomes Dying, via `juju destroy-unit`; or
    83        * the last Alive relation between its service and its principal's service
    84          is no longer Alive. This may come about via `juju destroy-relation`.
    85    * When any unit is Dying, its UA is responsible for removing impediments to
    86      the unit becoming Dead, and then making it so. To do so, the UA must:
    87        * Depart from all its relations in an orderly fashion.
    88        * Wait for all its subordinates to become Dead, and remove them from state.
    89        * Set its unit to Dead.
    90    * As just noted, when a subordinate unit is Dead, it is removed from state by
    91      its principal's UA; the relationship is the same as that of a principal unit
    92      to its assigned machine agent, and of a machine to the JobManageEnviron
    93      machine agent.
    94  
    95  Services
    96  --------
    97  
    98    * Services are created with `juju deploy`. Services with duplicate names
    99      are not allowed (units and machine with duplicate names are not possible:
   100      their identifiers are assigned by juju).
   101    * Unlike units and machines, services have no corresponding agent.
   102    * In addition, services become Dead and are removed from the database in a
   103      single atomic operation.
   104    * When a service is Alive, units may be added to it, and relations can be
   105      added using the service's endpoints.
   106    * A service can be destroyed at any time, via `juju destroy-service`. This
   107      causes all the units to become Dying, as discussed above, and will also
   108      cause all relations in which the service is participating to become Dying
   109      or be removed.
   110    * If a destroyed service has no units, and all its relations are eligible
   111      for immediate removal, then the service will also be removed immediately
   112      rather than being set to Dying.
   113    * If no associated relations exist, the service is removed by the MA which
   114      removes the last unit of that service from state.
   115    * If no units of the service remain, but its relations still exist, the
   116      responsibility for removing the service falls to the last UA to leave scope
   117      for that relation. (Yes, this is a UA for a unit of a totally different
   118      service.)
   119  
   120  Relations
   121  ---------
   122  
   123    * A relation is created with `juju add-relation`. No two relations with the
   124      same canonical name can exist. (The canonical relation name form is
   125      "<requirer-endpoint> <provider-endpoint>", where each endpoint takes the
   126      form "<service-name>:<charm-relation-name>".)
   127        * Thanks to convention, the above is not strictly true: it is possible
   128          for a subordinate charm to require a container-scoped "juju-info"
   129          relation. These restrictions mean that the name can never cause
   130          actual ambiguity; nonetheless, support should be phased out smoothly
   131          (see lp:1100076).
   132    * A relation, like a service, has no corresponding agent; and becomes Dead
   133      and is removed from the database in a single operation.
   134    * Similarly to a service, a relation cannot be created while an identical
   135      relation exists in state (in which identity is determined by equality of
   136      canonical relation name -- a sequence of endpoint pairs sorted by role).
   137    * While a relation is Alive, units of services in that relation can enter its
   138      scope; that is, the UAs for those units can signal to the system that they
   139      are participating in the relation.
   140    * A relation can be destroyed with either `juju destroy-relation` or
   141      `juju destroy-service`.
   142    * When a relation is destroyed with no units in scope, it will immediately
   143      become Dead and be removed from state, rather than being set to Dying.
   144    * When a relation becomes Dying, the UAs of units that have entered its scope
   145      are responsible for cleanly departing the relation by running hooks and then
   146      leaving relation scope (signalling that they are no longer participating).
   147    * When the last unit leaves the scope of a Dying relation, it must remove the
   148      relation from state.
   149    * As noted above, the Dying relation may be the only thing keeping a Dying
   150      service (different to that of the acting UA) from removal; so, relation
   151      removal may also imply service removal.
   152  
   153  References
   154  ----------
   155  
   156  OK, that was a bit of a hail of bullets, and the motivations for the above are
   157  perhaps not always clear. To consider it from another angle:
   158  
   159    * Subordinate units reference principal units.
   160    * Principal units reference machines.
   161    * All units reference their services.
   162    * All units reference the relations whose scopes they have joined.
   163    * All relations reference the services they are part of.
   164  
   165  In every case above, where X references Y, the life state of an X may be
   166  sufficient to prevent a change in the life state of a Y; and, conversely, a
   167  life change in an X may be sufficient to cause a life change in a Y. (In only
   168  one case does the reverse hold -- that is, setting a service or relation to
   169  Dying will cause appropriate units' agents to individually set their units to
   170  Dying -- and this is just an implementation detail.)
   171  
   172  The following scrawl may help you to visualize the references in play:
   173  
   174          +-----------+       +---------+
   175      +-->| principal |------>| machine |
   176      |   +-----------+       +---------+
   177      |      |     |
   178      |      |     +--------------+
   179      |      |                    |
   180      |      V                    V
   181      |   +----------+       +---------+
   182      |   | relation |------>| service |
   183      |   +----------+       +---------+
   184      |      A                    A
   185      |      |                    |
   186      |      |     +--------------+
   187      |      |     |
   188      |   +-------------+
   189      +---| subordinate |
   190          +-------------+
   191  
   192  ...but is important to remember that it's only one view of the relationships
   193  involved, and that the user-centric view is quite different; from a user's
   194  perspective the influences appear to travel in the opposite direction:
   195  
   196    * (destroying a machine "would" destroy its principals but that's disallowed)
   197    * destroying a principal destroys all its subordinates
   198    * (destroying a subordinate directly is impossible)
   199    * destroying a service destroys all its units and relations
   200    * destroying a container relation destroys all subordinates in the relation
   201    * (destroying a global relation destroys nothing else)
   202  
   203  ...and it takes a combination of these viewpoints to understand the detailed
   204  interactions laid out above.
   205  
   206  Agents
   207  ------
   208  
   209  It may also be instructive to consider the responsibilities of the unit and
   210  machine agents. The unit agent is responsible for:
   211  
   212    * detecting Alive relations incorporating its service and entering their
   213      scopes (if a principal, this may involve creating subordinates).
   214    * detecting Dying relations whose scope it has entered and leaving their
   215      scope (this involves removing any relations or services that thereby
   216      become unreferenced).
   217    * detecting undeployed Alive subordinates and deploying them.
   218    * detecting undeployed non-Alive subordinates and removing them (this raises
   219      similar questions to those alluded to above re Dying units on Dying machines:
   220      but, without persistent storage, there's no point deploying a Dying unit just
   221      to wait for its agent to set itself to Dead).
   222    * detecting deployed Dead subordinates, recalling them, and removing them.
   223    * detecting its service's Dying state, and setting its own Dying state.
   224    * if a subordinate, detecting that no relations with its principal are Alive,
   225      and setting its own Dying state.
   226    * detecting its own Dying state, and:
   227        * leaving all its relation scopes;
   228        * waiting for all its subordinates to be removed;
   229        * setting its own Dead state.
   230  
   231  A machine agent's responsibilities are determined by its jobs. There are only
   232  two jobs in existence at the moment; an MA whose machine has JobHostUnits is
   233  responsible for:
   234  
   235    * detecting undeployed Alive principals assigned to it and deploying them.
   236    * detecting undeployed non-Alive principals assigned to it and removing them
   237      (recall that unit removal may imply service removal).
   238    * detecting deployed Dead principals assigned to it, recalling them, and
   239      removing them.
   240    * detecting deployed principals not assigned to it, and recalling them.
   241    * detecting its machine's Dying state, and setting it to Dead.
   242  
   243  ...while one whose machine has JobManageEnviron is responsible for:
   244  
   245    * detecting Alive machines without instance IDs and provisioning provider
   246      instances to run their agents.
   247    * detecting non-Alive machines without instance IDs and removing them.
   248    * detecting Dead machines with instance IDs, decommissioning the instance, and
   249      removing the machine.
   250  
   251  Machines can in theory have multiple jobs, but in current practice do not.
   252  
   253  Implementation
   254  --------------
   255  
   256  All state change operations are mediated by the mgo/txn package, which provides
   257  multi-document transactions aginst MongoDB. This allows us to enforce the many
   258  conditions described above without experiencing races, so long as we are mindful
   259  when implementing them.
   260  
   261  Lifecycle support is not complete: relation lifecycles are, mostly, as are
   262  large parts of the unit and machine agent; but substantial parts of the
   263  machine, unit and service entity implementation still lack sophistication.
   264  This situation is being actively addressed.
   265  
   266  Beyond the plans detailed above, it is important to note that an agent that is
   267  failing to meet its responsibilities can have a somewhat distressing impact on
   268  the rest of the system. To counteract this, we intend to implement a --force
   269  flag to destroy-unit (and destroy-machine?) that forcibly sets an entity to
   270  Dead while maintaining consistency and sanity across all references. The best
   271  approach to this problem has yet to be agreed; we're not short of options, but
   272  none are exceptionally compelling.