Copyright @ Lenovo US

    This charm is created to demonstrate chained states using Juju charm. Chained states is essentially mirroring a pattern of any sequential execution in a workflow. Potentially each execution block can also have conditions to set the next state, even though this type of knowledge should be exposed outside function element, if possible, and to be handled by something better than pure code (eg. BPMN).

    The model for this experiment is straightforward. We create a layer with three states: state.1, state.2, and state.3. Upon start charm kicks off execution of state.1, which then transit itself to the state.2, then to state.3, and then loop back to state.1.

    Charm design pattern: chain states

    The key questions to answer in this experiment are:

    1. What is the entry point to start the first state?
    2. If setting two states true, are they executed serially or in parallel?
    3. Can a blocking command halt state transition even if there are states being true and can be acted upon?

    Screencast

    Top left window shows the juju debug-log which prints state transition among three states. Top right window juju status also shows state transitions in Message column which is set by set_status in each state's function block.

    Charm chain states screencast

    The 1st state

    How to start the first state?

    In this test we experimented using hooks to introduce the first state since hooks are executed in a predetermined sequence. However, set_state has no effect and actually should be avoided within hook execution according to document (needs reference).

    To safely start the whole process, we settled on @only_once:

    @only_once
    def state_0():
        log('something------------------')
    

    Chain state pattern

    The three primary states follow the same pattern. Using state.1 for example:

    @when('state.1')
    def state_1():
        """State.1
        """
    
        # set status
        t = time.ctime(time.time())
        status_set('maintenance', 'state.1 %s' % t)
    
        # workload
        time.sleep(TEST_TIMEOUT)
    
        # state transition
        remove_state('state.1')
        set_state('state.2')
    

    Multiple states being true

    If we set multiple states true, will they be executed in parallel?

    From previous article on state execution, we can already see that states are first saved in a dictionary and then scanned by iterator. Therefore, there is no parallel computing built in the charm execution mechanism. Further, execution order of two states have no guarantee except they will all be done sooner or later because Python dictionary does not enforce any order.

    Multiple true states will be executed in serial. Orders of execution is undetermined.

    Long running process

    Will a shell blocking call halt state transition?

    In this test we want to verify whether starting a long running process will block charm's state transition. We used subprocess.check_all to start a blocking call while state 1-3 are kept to loop as designed.

    def state_4():
        """State4.
        """
        subprocess.check_all("apt update && apt dist-upgrade")
    

    The result is clear that state machine will come to a halt at this blocking call, which would have to be the case since we already know how states are being scanned and executed from previous article. All states are cached in a dictionary and are scanned in a tight loop per iteration. Thus a blocking call in any handler will cause the loop to a halt. Nowhere in code will take a signal so this behavior can not be interruptted either.

    — by Feng Xia

    Related:

      2017-10-22
    Juju GUI nginx proxy

    In LXD on localhost we introduced using LXD container to bootstrap a Juju controller. But how to access the Juju GUI? Launching it is easy enough with $ juju gui from juju host; ...

      2017-09-06
    Juju local LXD

    Using Juju's LXD provider is the least-hassle way to start an experience of Juju and its charms. However, if you have done charm development for a while, you know making a one line of code ...

      2017-07-06
    Charm Ansible integration

    Let's face it. Ansible has the mouth (and market) share these days. For our modeling purpose, we are to utilize its procedural strength to carry out actions, which provides an abstraction instead of coding in charm's Python files.

    Design ...