From 19077c2754a4296a87a80679e876e67cfed57c5c Mon Sep 17 00:00:00 2001 From: Tim Van Steenburgh Date: Wed, 21 Dec 2016 10:59:44 -0500 Subject: [PATCH] Docs --- docs/narrative/model.rst | 95 ++++++++++++++++++++++++++++++++++++++++ juju/client/overrides.py | 22 ++++++++-- juju/model.py | 8 ++++ 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/docs/narrative/model.rst b/docs/narrative/model.rst index 6811eac..036f43f 100644 --- a/docs/narrative/model.rst +++ b/docs/narrative/model.rst @@ -129,3 +129,98 @@ Example of creating a new model and then destroying it. See await model.disconnect() await controller.destroy_model(model.info.uuid) model = None + + +Reacting to Changes in a Model +------------------------------ +To watch for and respond to changes in a model, register an observer with the +model. The easiest way to do this is by creating a +:class:`juju.model.ModelObserver` subclass. + +.. code:: python + + from juju.model import Model, ModelObserver + + class MyModelObserver(ModelObserver): + async def on_change(self, delta, old, new, model): + # The raw change data (dict) from the websocket. + print(delta.data) + + # The entity type (str) affected by this change. + # One of ('action', 'application', 'annotation', 'machine', + # 'unit', 'relation') + print(delta.entity) + + # The type (str) of change. + # One of ('add', 'change', 'remove') + print(delta.type) + + # The 'old' and 'new' parameters are juju.model.ModelEntity + # instances which represent an entity in the model both before + # this change was applied (old) and after (new). + + # If an entity is being added to the model, the 'old' param + # will be None. + if delta.type == 'add': + assert(old is None) + + # If an entity is being removed from the model, the 'new' param + # will be None. + if delta.type == 'remove': + assert(new is None) + + # The 'old' and 'new' parameters, when not None, will be instances + # of a juju.model.ModelEntity subclass. The type of the subclass + # depends on the value of 'delta.entity', for example: + # + # delta.entity type + # ------------ ---- + # 'action' -> juju.action.Action + # 'application' -> juju.application.Application + # 'annotation' -> juju.annotation.Annotation + # 'machine' -> juju.machine.Machine + # 'unit' -> juju.unit.Unit + # 'relation' -> juju.relation.Relation + + # Finally, the 'model' parameter is a reference to the + # juju.model.Model instance to which this observer is attached. + print(id(model)) + + + model = Model() + await model.connect_current() + + model.add_observer(MyModelObserver()) + + +Every change in the model will result in a call to the `on_change()` +method of your observer(s). + +To target your code more precisely, define method names that correspond +to the entity and type of change that you wish to handle. + +.. code:: python + + from juju.model import Model, ModelObserver + + class MyModelObserver(ModelObserver): + async def on_application_change(self, delta, old, new, model): + # Both 'old' and 'new' params will be instances of + # juju.application.Application + pass + + async def on_unit_remove(self, delta, old, new, model): + # Since a unit is being removed, the 'new' param will always + # be None in this handler. The 'old' param will be an instance + # of juju.unit.Unit - the state of the unit before it was removed. + pass + + async def on_machine_add(self, delta, old, new, model): + # Since a machine is being added, the 'old' param will always be + # None in this handler. The 'new' param will be an instance of + # juju.machine.Machine. + pass + + async def on_change(self, delta, old, new, model): + # The catch-all handler - will be called whenever a more + # specific handler method is not defined. diff --git a/juju/client/overrides.py b/juju/client/overrides.py index 01c9a60..3f3caa4 100644 --- a/juju/client/overrides.py +++ b/juju/client/overrides.py @@ -8,13 +8,29 @@ __all__ = [ class Delta(Type): + """A single websocket delta. + + :ivar entity: The entity name, e.g. 'unit', 'application' + :vartype entity: str + + :ivar type: The delta type, e.g. 'add', 'change', 'remove' + :vartype type: str + + :ivar data: The raw delta data + :vartype data: dict + + NOTE: The 'data' variable above is being incorrectly cross-linked by a + Sphinx bug: https://github.com/sphinx-doc/sphinx/issues/2549 + + """ _toSchema = {'deltas': 'deltas'} _toPy = {'deltas': 'deltas'} def __init__(self, deltas=None): - ''' - deltas : [str, str, object] - ''' + """ + :param deltas: [str, str, object] + + """ self.deltas = deltas Change = namedtuple('Change', 'entity type data') diff --git a/juju/model.py b/juju/model.py index a0180a0..7622178 100644 --- a/juju/model.py +++ b/juju/model.py @@ -74,6 +74,14 @@ class ModelObserver(object): await method(delta, old, new, model) async def on_change(self, delta, old, new, model): + """Generic model-change handler. + + :param delta: :class:`juju.client.overrides.Delta` + :param old: :class:`juju.model.ModelEntity` + :param new: :class:`juju.model.ModelEntity` + :param model: :class:`juju.model.Model` + + """ pass -- 2.25.1