openstack-charmers / zaza

A Python3-only functional test framework for Charms
Apache License 2.0
10 stars 46 forks source link

Fix `unit.run` to support Juju 2.9 and 3.x #655

Closed rgildein closed 4 months ago

rgildein commented 4 months ago

The run_on_unit require to be awaited for juju 3+, and this fix proposes a solution to check status of action and wait for it if it's "pending". This was original described in issue #649 and marked as fixed by #650, however the action object is never awaitable as it can be seen in my examples below.

I tested in with this script

import asyncio
import inspect
from juju.model import Model

async def run_test_command():
    model = Model()
    await model.connect(model_name="test")
    # try to run command
    try:
        action = await model.units["grafana/0"].run("echo HelloWord")
        print("command isawaitable: ", inspect.isawaitable(action))
        print("command action.data: ", action.data)
        print("command action.status: ", action.status)
        print("command action.results: ", action.results)
        if action.status == "pending":
            await action.wait()
        print("command isawaitable: ", inspect.isawaitable(action))
        print("command action.data: ", action.data)
        print("command action.status: ", action.status)
        print("command action.results: ", action.results)
    except Exception as error:
        print(error)
    # try to run actions get-admin-password
    try:
        action = await model.units["grafana/0"].run("actions/get-admin-password")  # `actions/` needs to be specified in Juju 2.9
        print("command isawaitable: ", inspect.isawaitable(action))
        print("command action.data: ", action.data)
        print("command action.status: ", action.status)
        print("command action.results: ", action.results)
        if action.status == "pending":
            await action.wait()
        print("command isawaitable: ", inspect.isawaitable(action))
        print("command action.data: ", action.data)
        print("command action.status: ", action.status)
        print("command action.results: ", action.results)
    except Exception as error:
        print(error)

and here are the results for Juju 2.9

(.venv) ubuntu@rgildein-bastion:~$ juju status
Model  Controller             Cloud/Region             Version  SLA          Timestamp
test   rgildein2-serverstack  serverstack/serverstack  2.9.35   unsupported  18:40:23Z

App      Version  Status  Scale  Charm    Channel  Rev  Exposed  Message
grafana           active      1  grafana  stable    69  no       Ready

Unit        Workload  Agent  Machine  Public address  Ports     Message
grafana/0*  active    idle   0        10.5.1.81       3000/tcp  Ready

Machine  State    Address    Inst id                               Series  AZ    Message
0        started  10.5.1.81  049ee5ba-4cff-4b41-bdca-1f18d676043f  focal   nova  ACTIVE

(.venv) ubuntu@rgildein-bastion:~$ pip freeze | grep juju
juju==2.9.46.1
jujubundlelib==0.5.7
(.venv) ubuntu@rgildein-bastion:~$ python3 ./zaza-test-script.py 
command isawaitable:  False
command action.data:  {'model-uuid': '5972fd83-b71d-4746-8dde-11b1ab1026f5', 'id': '24', 'receiver': 'grafana/0', 'name': 'juju-run', 'parameters': {'command': 'echo HelloWord', 'timeout': 0, 'workload-context': False}, 'status': 'completed', 'message': '', 'results': {'Code': '0', 'Stdout': 'HelloWord\n'}, 'enqueued': '2024-04-15T18:40:51Z', 'started': '2024-04-15T18:40:54Z', 'completed': '2024-04-15T18:40:54Z'}
command action.status:  completed
command action.results:  {'Code': '0', 'Stdout': 'HelloWord\n'}
command isawaitable:  False
command action.data:  {'model-uuid': '5972fd83-b71d-4746-8dde-11b1ab1026f5', 'id': '24', 'receiver': 'grafana/0', 'name': 'juju-run', 'parameters': {'command': 'echo HelloWord', 'timeout': 0, 'workload-context': False}, 'status': 'completed', 'message': '', 'results': {'Code': '0', 'Stdout': 'HelloWord\n'}, 'enqueued': '2024-04-15T18:40:51Z', 'started': '2024-04-15T18:40:54Z', 'completed': '2024-04-15T18:40:54Z'}
command action.status:  completed
command action.results:  {'Code': '0', 'Stdout': 'HelloWord\n'}
command isawaitable:  False
command action.data:  {'model-uuid': '5972fd83-b71d-4746-8dde-11b1ab1026f5', 'id': '26', 'receiver': 'grafana/0', 'name': 'juju-run', 'parameters': {'command': 'actions/get-admin-password', 'timeout': 0, 'workload-context': False}, 'status': 'completed', 'message': '', 'results': {'Code': '0', 'password': 'K5xgXHBM4jYwwtgt'}, 'enqueued': '2024-04-15T18:40:54Z', 'started': '2024-04-15T18:40:54Z', 'completed': '2024-04-15T18:40:55Z'}
command action.status:  completed
command action.results:  {'Code': '0', 'password': 'K5xgXHBM4jYwwtgt'}
command isawaitable:  False
command action.data:  {'model-uuid': '5972fd83-b71d-4746-8dde-11b1ab1026f5', 'id': '26', 'receiver': 'grafana/0', 'name': 'juju-run', 'parameters': {'command': 'actions/get-admin-password', 'timeout': 0, 'workload-context': False}, 'status': 'completed', 'message': '', 'results': {'Code': '0', 'password': 'K5xgXHBM4jYwwtgt'}, 'enqueued': '2024-04-15T18:40:54Z', 'started': '2024-04-15T18:40:54Z', 'completed': '2024-04-15T18:40:55Z'}
command action.status:  completed
command action.results:  {'Code': '0', 'password': 'K5xgXHBM4jYwwtgt'}

and results for Juju 3.4:

(.venv) ubuntu@juju-lxd-34:~$ juju status
Model  Controller  Cloud/Region         Version  SLA          Timestamp
test   lxd         localhost/localhost  3.4.2    unsupported  18:42:50Z

App      Version  Status  Scale  Charm    Channel        Rev  Exposed  Message
grafana           active      1  grafana  latest/stable   69  no       Ready

Unit        Workload  Agent  Machine  Public address  Ports     Message
grafana/0*  active    idle   0        10.205.200.72   3000/tcp  Ready

Machine  State    Address        Inst id        Base          AZ  Message
0        started  10.205.200.72  juju-1d3ff7-0  ubuntu@20.04      Running
(.venv) ubuntu@juju-lxd-34:~$ pip freeze | grep juju
juju==3.4.0.0
(.venv) ubuntu@juju-lxd-34:~$ python3 ./zaza-test-script.py 
command isawaitable:  False
command action.data:  {'model-uuid': 'a330379b-c75f-4a98-8726-10dfd71d3ff7', 'id': '30', 'receiver': 'grafana/0', 'name': 'juju-exec', 'status': 'pending', 'message': '', 'enqueued': '2024-04-15T18:43:15Z', 'started': '0001-01-01T00:00:00Z', 'completed': '0001-01-01T00:00:00Z'}
command action.status:  pending
command action.results:  {}
command isawaitable:  False
command action.data:  {'model-uuid': 'a330379b-c75f-4a98-8726-10dfd71d3ff7', 'id': '30', 'receiver': 'grafana/0', 'name': 'juju-exec', 'status': 'completed', 'message': '', 'enqueued': '2024-04-15T18:43:15Z', 'started': '2024-04-15T18:43:15Z', 'completed': '2024-04-15T18:43:15Z'}
command action.status:  completed
command action.results:  {'return-code': 0, 'stdout': 'HelloWord\n'}
command isawaitable:  False
command action.data:  {'model-uuid': 'a330379b-c75f-4a98-8726-10dfd71d3ff7', 'id': '32', 'receiver': 'grafana/0', 'name': 'juju-exec', 'status': 'pending', 'message': '', 'enqueued': '2024-04-15T18:43:16Z', 'started': '0001-01-01T00:00:00Z', 'completed': '0001-01-01T00:00:00Z'}
command action.status:  pending
command action.results:  {}
command isawaitable:  False
command action.data:  {'model-uuid': 'a330379b-c75f-4a98-8726-10dfd71d3ff7', 'id': '32', 'receiver': 'grafana/0', 'name': 'juju-exec', 'status': 'completed', 'message': '', 'enqueued': '2024-04-15T18:43:16Z', 'started': '2024-04-15T18:43:16Z', 'completed': '2024-04-15T18:43:17Z'}
command action.status:  completed
command action.results:  {'password': 'pxVVZpZGrcgCdqpH', 'return-code': 0}

The example of usage on both 2.9 and 3.4 (see logs) can be found here. The func tests are failing, but it's not related with zaza. fixes: https://github.com/openstack-charmers/zaza/issues/649

freyes commented 4 months ago

I will run this change in one of the charms, with the CI. - https://review.opendev.org/c/openstack/charm-mysql-innodb-cluster/+/915994

freyes commented 4 months ago

@rgildein , can you take the chance of enabling juju 3.4 in the CI? - https://github.com/openstack-charmers/zaza/blob/master/.github/workflows/tox.yaml#L38 .

rgildein commented 4 months ago

@rgildein , can you take the chance of enabling juju 3.4 in the CI? - https://github.com/openstack-charmers/zaza/blob/master/.github/workflows/tox.yaml#L38 .

Done

codecov[bot] commented 4 months ago

Codecov Report

All modified and coverable lines are covered by tests :white_check_mark:

Project coverage is 89.53%. Comparing base (b22c2ee) to head (8b06c8e). Report is 2 commits behind head on master.

:exclamation: Current head 8b06c8e differs from pull request most recent head 14bab3a. Consider uploading reports for the commit 14bab3a to get more accurate results

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #655 +/- ## ========================================== - Coverage 89.54% 89.53% -0.01% ========================================== Files 45 45 Lines 4762 4759 -3 ========================================== - Hits 4264 4261 -3 Misses 498 498 ```

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

freyes commented 4 months ago

LGTM. Thanks for the effort put into this. I'm just waiting for the CI results on this change - https://review.opendev.org/c/openstack/charm-mysql-innodb-cluster/+/915994 - to merge.

note: the ci failure in the 'third' test, it's not related to this change.

jammy https://openstack-ci-reports.ubuntu.com/artifacts/f20/915994/2/check/jammy/f2025fa/ : SUCCESS in 1h 18m 51s

the focal job failed, because an undercloud issue, so I won't block this PR on that.