juju / python-libjuju

Python library for the Juju API
Apache License 2.0
60 stars 100 forks source link

`unit.is_leader_from_status` reports False for all units of a subordinate charm #374

Closed jguedez closed 4 years ago

jguedez commented 4 years ago

Context python-libjuju v2.6.3 juju --version => 2.6.10-bionic-amd64 (snap)

This affects the migration of the functional test of openstack charms to the zaza testing framework, as some of them are deployed as subordinates (neutron-openvswitch and others in https://bugs.launchpad.net/charm-aodh/+bug/1828424)

How to reproduce:

Start with a deployed bundle including subordinate charms (e.g. neutron-openvswitch below). juju status reports a leader: neutron-openvswitch/0*

image

However unit.is_leader_from_status (https://github.com/juju/python-libjuju/blob/master/juju/unit.py#L246) reports False for all units. There is a comment in the code about returning False for subordinates on purpose. However as shown above, juju status does report a leader. juju run --unit neutron-openvswitch/leader <cmd> does work as expected as well.

Code to reproduce the issue:

from juju import loop
from juju.model import Model

async def subordinate_has_no_leader():
    model = Model()
    await model.connect()

    app_name = 'neutron-openvswitch'
    app_ovs = model.applications[app_name]
    print("app: {}, units: {}".format(app_name, app_ovs.units))

    for unit in app_ovs.units:
        print("unit: {}, leader?: {}".format(unit.entity_id,
            await unit.is_leader_from_status()))

    await model.disconnect()

if __name__ == "__main__":
    loop.run(subordinate_has_no_leader())

which outputs the following for the model above (works fine for a principle charm):

$ python reproduce.py
app: neutron-openvswitch, units: [<Unit entity_id="neutron-openvswitch/1">, <Unit entity_id="neutron-openvswitch/0">]
unit: neutron-openvswitch/1, leader?: False
unit: neutron-openvswitch/0, leader?: False
jguedez commented 4 years ago

Did not want to file another issue, since this is probably the root cause for the problem above. But calls to model.get_status() actually return no units for subordinate charms even though the application itself is in the data structure returned:

from juju import loop
from juju.model import Model

async def subordinate_has_no_units():
    model = Model()
    await model.connect()

    app_name = 'neutron-openvswitch'
    app_ovs = model.applications[app_name]
    print("app: {}, units: {}".format(app_name, app_ovs.units))

    model_status = await model.get_status()

    print("model status units is None: {}".format(
        model_status.applications[app_name]["units"] is None))

    await model.disconnect()

if __name__ == "__main__":
    loop.run(subordinate_has_no_units())

which outputs the following for the model above (works fine for a principle charm):

$ python reproduce2.py
app: neutron-openvswitch, units: [<Unit entity_id="neutron-openvswitch/1">, <Unit entity_id="neutron-openvswitch/0">]
model status units is None: True
hpidcock commented 4 years ago

@jguedez Thank-you for giving us all the good detail. This has been fixed in master. Please let us know if there is any further issues.