canonical / jhack

Chock-full of Juju hackery.
Apache License 2.0
50 stars 24 forks source link

`show-relation` fails on surbordinate applications #179

Open gboutry opened 2 months ago

gboutry commented 2 months ago

Trying to show relation of subordinate charm fails.

I tried to read the peer data of a surbordinate charm:

$ jhack show-relation ntp:ntp-peers
...
| /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:304 in                  │
│ get_metadata_from_status                                                                         │
│                                                                                                  │
│    301 ):                                                                                        │
│    302 │   status = _juju_status(model=model, json=True)                                         │
│    303 │   # machine status json output apparently has no 'scale'... -_-                         │
│ ❱  304 │   app_status = status["applications"][endpoint.app_name]                                │
│    305 │   if app_status.get("subordinate-to"):                                                  │
│    306 │   │   units = {}                                                                        │
│    307 │   │   # todo: need to scavenge unit names from OTHER units' .subordinates field         │
│                                                                                                  │
│ ╭────────── locals ──────────╮                                                                   │
│ │ endpoint = 'ntp:ntp-peers' │                                                                   │
│ │    model = None            │                                                                   │
│ │   status = {}              │                                                                   │
│ ╰────────────────────────────╯                                                                   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyError: 'applications'

I tried reading juju-info:

$ jhack show-relation ntp:juju-info sunbeam-charms:juju-info
...
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:725 in                  │
│ _coalesce_endpoint_and_n                                                                         │
│                                                                                                  │
│    722 │   │   # if either provider or requirer are not apps in this model, OR either one have   │
│    723 │   │   # suspect a malformed CMR request                                                 │
│    724 │   │   status = _juju_status(model=model, json=True)                                     │
│ ❱  725 │   │   apps = status["applications"]                                                     │
│    726 │   │   app1 = apps.get(ep_url_1.app_name)                                                │
│    727 │   │   app2 = apps.get(ep_url_2.app_name)                                                │
│    728 │   │   app_not_found = (                                                                 │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │ endpoint1 = 'ntp:juju-info'                                                                  │ │
│ │ endpoint2 = 'sunbeam-charms:juju-info'                                                       │ │
│ │  ep_url_1 = 'ntp:juju-info'                                                                  │ │
│ │  ep_url_2 = 'sunbeam-charms:juju-info'                                                       │ │
│ │      flip = False                                                                            │ │
│ │     found = []                                                                               │ │
│ │     match = False                                                                            │ │
│ │     model = None                                                                             │ │
│ │       msg = "No relation found with endpoints 'ntp:juju-info' -> 'sunbeam-charms:juju-info'  │ │
│ │             i"+30                                                                            │ │
│ │         n = None                                                                             │ │
│ │  relation = Relation(                                                                        │ │
│ │             │   provider='sunbeam-machine',                                                  │ │
│ │             │   provider_endpoint='juju-info',                                               │ │
│ │             │   requirer='ntp',                                                              │ │
│ │             │   requirer_endpoint='juju-info',                                               │ │
│ │             │   interface='juju-info',                                                       │ │
│ │             │   raw_type='subordinate'                                                       │ │
│ │             )                                                                                │ │
│ │ relations = [                                                                                │ │
│ │             │   Relation(                                                                    │ │
│ │             │   │   provider='mysql',                                                        │ │
│ │             │   │   provider_endpoint='database-peers',                                      │ │
│ │             │   │   requirer='mysql',                                                        │ │
│ │             │   │   requirer_endpoint='database-peers',                                      │ │
│ │             │   │   interface='mysql_peers',                                                 │ │
│ │             │   │   raw_type='peer'                                                          │ │
│ │             │   ),                                                                           │ │
│ │             │   Relation(                                                                    │ │
│ │             │   │   provider='mysql',                                                        │ │
│ │             │   │   provider_endpoint='restart',                                             │ │
│ │             │   │   requirer='mysql',                                                        │ │
│ │             │   │   requirer_endpoint='restart',                                             │ │
│ │             │   │   interface='rolling_op',                                                  │ │
│ │             │   │   raw_type='peer'                                                          │ │
│ │             │   ),                                                                           │ │
│ │             │   Relation(                                                                    │ │
│ │             │   │   provider='mysql',                                                        │ │
│ │             │   │   provider_endpoint='upgrade',                                             │ │
│ │             │   │   requirer='mysql',                                                        │ │
│ │             │   │   requirer_endpoint='upgrade',                                             │ │
│ │             │   │   interface='upgrade',                                                     │ │
│ │             │   │   raw_type='peer'                                                          │ │
│ │             │   ),                                                                           │ │
│ │             │   Relation(                                                                    │ │
│ │             │   │   provider='ntp',                                                          │ │
│ │             │   │   provider_endpoint='ntp-peers',                                           │ │
│ │             │   │   requirer='ntp',                                                          │ │
│ │             │   │   requirer_endpoint='ntp-peers',                                           │ │
│ │             │   │   interface='ntp',                                                         │ │
│ │             │   │   raw_type='peer'                                                          │ │
│ │             │   ),                                                                           │ │
│ │             │   Relation(                                                                    │ │
│ │             │   │   provider='sunbeam-machine',                                              │ │
│ │             │   │   provider_endpoint='juju-info',                                           │ │
│ │             │   │   requirer='ntp',                                                          │ │
│ │             │   │   requirer_endpoint='juju-info',                                           │ │
│ │             │   │   interface='juju-info',                                                   │ │
│ │             │   │   raw_type='subordinate'                                                   │ │
│ │             │   )                                                                            │ │
│ │             ]                                                                                │ │
│ │    status = {}                                                                               │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyError: 'applications'

Status output:

$ juju status --relations
Model   Controller  Cloud/Region         Version  SLA          Timestamp
testos  lxd         localhost/localhost  3.5.3    unsupported  14:42:54+02:00

App              Version  Status  Scale  Charm            Channel        Rev  Exposed  Message
ntp              4.2      active      5  ntp              latest/stable   50  no       chrony: Ready
sunbeam-machine           active      5  sunbeam-machine  2024.1/edge     36  no       

Unit                Workload  Agent  Machine  Public address                          Ports    Message
sunbeam-machine/0*  active    idle   1        fd00:56ad:9f7a:9800:216:3eff:fe8f:5914           
  ntp/5             active    idle            fd00:56ad:9f7a:9800:216:3eff:fe8f:5914  123/udp  chrony: Ready
sunbeam-machine/1   active    idle   2        fd00:56ad:9f7a:9800:216:3eff:fe39:b945           
  ntp/0             active    idle            fd00:56ad:9f7a:9800:216:3eff:fe39:b945  123/udp  chrony: Ready
sunbeam-machine/2   active    idle   3        fd00:56ad:9f7a:9800:216:3eff:fe74:b927           
  ntp/1*            active    idle            fd00:56ad:9f7a:9800:216:3eff:fe74:b927  123/udp  chrony: Ready
sunbeam-machine/3   active    idle   4        fd00:56ad:9f7a:9800:216:3eff:fe3c:37ca           
  ntp/4             active    idle            fd00:56ad:9f7a:9800:216:3eff:fe3c:37ca  123/udp  chrony: Ready
sunbeam-machine/4   active    idle   5        fd00:56ad:9f7a:9800:216:3eff:febe:90a5           
  ntp/3             active    idle            fd00:56ad:9f7a:9800:216:3eff:febe:90a5  123/udp  chrony: Ready

Machine  State    Address                                 Inst id        Base          AZ  Message
1        started  fd00:56ad:9f7a:9800:216:3eff:fe8f:5914  juju-a1d33d-1  ubuntu@22.04      Running
2        started  fd00:56ad:9f7a:9800:216:3eff:fe39:b945  juju-a1d33d-2  ubuntu@22.04      Running
3        started  fd00:56ad:9f7a:9800:216:3eff:fe74:b927  juju-a1d33d-3  ubuntu@22.04      Running
4        started  fd00:56ad:9f7a:9800:216:3eff:fe3c:37ca  juju-a1d33d-4  ubuntu@22.04      Running
5        started  fd00:56ad:9f7a:9800:216:3eff:febe:90a5  juju-a1d33d-5  ubuntu@22.04      Running

Integration provider       Requirer       Interface  Type         Message
ntp:ntp-peers              ntp:ntp-peers  ntp        peer         
sunbeam-machine:juju-info  ntp:juju-info  juju-info  subordinate        

jhack version: jhack 0.4.3.2.1 --DEVMODE-- juju version: 3.5.3


Note: if trying to reproduce with these 2 specific charms, know that sunbeam-machine and ntp won't work in a container, they need to be deployed on a VM (--constraints virt-type=virtual-machine to get a LXD vm on a LXD cloud)

PietroPasotti commented 2 months ago

Yeah in some situations juju status seems to be returning nothing, but I find it very hard to reproduce. I assume you retried soon after and didn't see changes, it wasn't a transient thing?

PietroPasotti commented 2 months ago

can you check if running the command with the LOGLEVEL=DEBUG envvar set gives you any more hints?

gboutry commented 2 months ago

I have a 100% failure rate until now

With the debug level:

LOGLEVEL=DEBUG jhack show-relation -m testos ntp:ntp-peers                         
INFO:jhack:jhack running in snapped mode. Checking configuration...
INFO:jhack:juju command is b'/snap/jhack/387/bin/juju\n'
DEBUG:parse:format '{_}: {timestamp:ti} {_}' -> '(.+?): (?P<timestamp>(\\d{4}-\\d\\d-\\d\\d)((\\s+|T)(\\d{1,2}:\\d{1,2}(:\\d{1,2}(\\.\\d+)?)?))?(Z|\\s*[-+]\\d\\d:?\\d\\d)?) (.+?)'
DEBUG:parse:format '{_}: {timestamp:tt} {_}' -> '(.+?): (?P<timestamp>(\\d{1,2}:\\d{1,2}(:\\d{1,2}(\\.\\d+)?)?)?(\\s+[AP]M)?(\\s+[-+]\\d\\d?:?\\d\\d)?) (.+?)'
::= Verbose mode (DEBUG). =::
DEBUG:asyncio:Using selector: EpollSelector
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:1023 in                 │
│ sync_show_relation                                                                               │
│                                                                                                  │
│   1020 │   - ``$ jhack utils show-relation my_app:peers`` - peer relation\n                      │
│   1021 │   - ``$ jhack utils show-relation my_app:foo cross_model_app:bar`` - CMRs\n             │
│   1022 │   """                                                                                   │
│ ❱ 1023 │   return _sync_show_relation(                                                           │
│   1024 │   │   endpoint1=endpoint1,                                                              │
│   1025 │   │   endpoint2=endpoint2,                                                              │
│   1026 │   │   n=n,                                                                              │
│                                                                                                  │
│ ╭────────────────── locals ───────────────────╮                                                  │
│ │               color = 'auto'                │                                                  │
│ │           endpoint1 = 'ntp:ntp-peers'       │                                                  │
│ │           endpoint2 = None                  │                                                  │
│ │              format = <Format.auto: 'auto'> │                                                  │
│ │ hide_empty_databags = False                 │                                                  │
│ │               model = 'testos'              │                                                  │
│ │                   n = None                  │                                                  │
│ │      show_juju_keys = False                 │                                                  │
│ │               watch = False                 │                                                  │
│ ╰─────────────────────────────────────────────╯                                                  │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:1062 in                 │
│ _sync_show_relation                                                                              │
│                                                                                                  │
│   1059 │   while True:                                                                           │
│   1060 │   │   start = time.time()                                                               │
│   1061 │   │                                                                                     │
│ ❱ 1062 │   │   table = asyncio.run(                                                              │
│   1063 │   │   │   render_relation(                                                              │
│   1064 │   │   │   │   endpoint1,                                                                │
│   1065 │   │   │   │   endpoint2,                                                                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               color = 'auto'                                                                 │ │
│ │             Console = <class 'rich.console.Console'>                                         │ │
│ │             console = <console width=249 ColorSystem.TRUECOLOR>                              │ │
│ │           endpoint1 = 'ntp:ntp-peers'                                                        │ │
│ │           endpoint2 = None                                                                   │ │
│ │              format = <Format.auto: 'auto'>                                                  │ │
│ │ hide_empty_databags = False                                                                  │ │
│ │               model = 'testos'                                                               │ │
│ │                   n = None                                                                   │ │
│ │                rich = <module 'rich' from                                                    │ │
│ │                       '/snap/jhack/387/lib/python3.8/site-packages/rich/__init__.py'>        │ │
│ │      show_juju_keys = False                                                                  │ │
│ │               start = 1724160271.643747                                                      │ │
│ │               watch = False                                                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /usr/lib/python3.8/asyncio/runners.py:44 in run                                                  │
│                                                                                                  │
│   41 │   │   events.set_event_loop(loop)                                                         │
│   42 │   │   if debug is not None:                                                               │
│   43 │   │   │   loop.set_debug(debug)                                                           │
│ ❱ 44 │   │   return loop.run_until_complete(main)                                                │
│   45 │   finally:                                                                                │
│   46 │   │   try:                                                                                │
│   47 │   │   │   _cancel_all_tasks(loop)                                                         │
│                                                                                                  │
│ ╭──────────────────────────────── locals ────────────────────────────────╮                       │
│ │ debug = None                                                           │                       │
│ │  loop = <_UnixSelectorEventLoop running=False closed=True debug=False> │                       │
│ │  main = <coroutine object render_relation at 0x70c74b6e7340>           │                       │
│ ╰────────────────────────────────────────────────────────────────────────╯                       │
│                                                                                                  │
│ /usr/lib/python3.8/asyncio/base_events.py:616 in run_until_complete                              │
│                                                                                                  │
│    613 │   │   if not future.done():                                                             │
│    614 │   │   │   raise RuntimeError('Event loop stopped before Future completed.')             │
│    615 │   │                                                                                     │
│ ❱  616 │   │   return future.result()                                                            │
│    617 │                                                                                         │
│    618 │   def stop(self):                                                                       │
│    619 │   │   """Stop running the event loop.                                                   │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │   future = <Task finished name='Task-1' coro=<render_relation() done, defined at             │ │
│ │            /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:789>     │ │
│ │            exception=KeyError('applications')>                                               │ │
│ │ new_task = True                                                                              │ │
│ │     self = <_UnixSelectorEventLoop running=False closed=True debug=False>                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:814 in render_relation  │
│                                                                                                  │
│    811 │   │   if endpoint1.app_name in saas or (endpoint2 and endpoint2.app_name in saas):      │
│    812 │   │   │   relation.raw_type = "cross_model"                                             │
│    813 │                                                                                         │
│ ❱  814 │   entities = _gather_entities(                                                          │
│    815 │   │   endpoint1,                                                                        │
│    816 │   │   endpoint2,                                                                        │
│    817 │   │   relation,                                                                         │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                 endpoint1 = 'ntp:ntp-peers'                    │                               │
│ │                 endpoint2 = None                               │                               │
│ │                    format = <Format.auto: 'auto'>              │                               │
│ │       hide_empty_databags = False                              │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                         n = None                               │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:765 in _gather_entities │
│                                                                                                  │
│    762 ) -> Tuple[AppRelationData, ...]:                                                         │
│    763 │   if relation.type == RelationType.peer:                                                │
│    764 │   │   return (                                                                          │
│ ❱  765 │   │   │   get_peer_relation_data(                                                       │
│    766 │   │   │   │   endpoint=endpoint1,                                                       │
│    767 │   │   │   │   include_default_juju_keys=include_default_juju_keys,                      │
│    768 │   │   │   │   model=model,                                                              │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                 endpoint1 = 'ntp:ntp-peers'                    │                               │
│ │                 endpoint2 = None                               │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:546 in                  │
│ get_peer_relation_data                                                                           │
│                                                                                                  │
│    543 │   include_default_juju_keys: bool = False,                                              │
│    544 │   model: str = None,                                                                    │
│    545 ) -> AppRelationData:                                                                     │
│ ❱  546 │   return get_content(                                                                   │
│    547 │   │   endpoint,                                                                         │
│    548 │   │   endpoint,                                                                         │
│    549 │   │   relation,                                                                         │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                  endpoint = 'ntp:ntp-peers'                    │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:374 in get_content      │
│                                                                                                  │
│    371 │   # so even though we need 'any' remote unit name, we still need to query the status    │
│    372 │   # to find out what units there are.                                                   │
│    373 │   status = _juju_status(model=model, json=True)                                         │
│ ❱  374 │   units, meta = get_units_and_meta(obj, model)                                          │
│    375 │                                                                                         │
│    376 │   if other_model != model:                                                              │
│    377 │   │   logger.info(f"other app is in model {other_model!r}. Pulling status...")          │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                       obj = 'ntp:ntp-peers'                    │                               │
│ │               other_model = None                               │                               │
│ │                 other_obj = 'ntp:ntp-peers'                    │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ │                    status = {}                                 │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:353 in                  │
│ get_units_and_meta                                                                               │
│                                                                                                  │
│    350 │   model: str = None,                                                                    │
│    351 ):                                                                                        │
│    352 │   """Get app name and unit count from url; url is either `app_name/0` or `app_name`.""  │
│ ❱  353 │   meta = get_metadata_from_status(endpoint, model=model)                                │
│    354 │   if endpoint.unit_id is not None:                                                      │
│    355 │   │   units = (int(endpoint.unit_id),)                                                  │
│    356 │   else:                                                                                 │
│                                                                                                  │
│ ╭────────── locals ──────────╮                                                                   │
│ │ endpoint = 'ntp:ntp-peers' │                                                                   │
│ │    model = 'testos'        │                                                                   │
│ ╰────────────────────────────╯                                                                   │
│                                                                                                  │
│ /snap/jhack/387/lib/python3.8/site-packages/jhack/utils/show_relation.py:304 in                  │
│ get_metadata_from_status                                                                         │
│                                                                                                  │
│    301 ):                                                                                        │
│    302 │   status = _juju_status(model=model, json=True)                                         │
│    303 │   # machine status json output apparently has no 'scale'... -_-                         │
│ ❱  304 │   app_status = status["applications"][endpoint.app_name]                                │
│    305 │   if app_status.get("subordinate-to"):                                                  │
│    306 │   │   units = {}                                                                        │
│    307 │   │   # todo: need to scavenge unit names from OTHER units' .subordinates field         │
│                                                                                                  │
│ ╭────────── locals ──────────╮                                                                   │
│ │ endpoint = 'ntp:ntp-peers' │                                                                   │
│ │    model = 'testos'        │                                                                   │
│ │   status = {}              │                                                                   │
│ ╰────────────────────────────╯                                                                   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyError: 'applications'
PietroPasotti commented 2 months ago

could you post the output of running the above after installing jhack from this branch? https://github.com/canonical/jhack/pull/180

gboutry commented 2 months ago

Of course:

$ LOGLEVEL=DEBUG jhack show-relation -m testos ntp:ntp-peers
INFO:jhack:jhack running in unsnapped mode. Skipping .local/share/juju configuration.
DEBUG:parse:format '{_}: {timestamp:ti} {_}' -> '(.+?): (?P<timestamp>(\\d{4}-\\d\\d-\\d\\d)((\\s+|T)(\\d{1,2}:\\d{1,2}(:\\d{1,2}(\\.\\d+)?)?))?(Z|\\s*[-+]\\d\\d:?\\d\\d)?) (.+?)'
DEBUG:parse:format '{_}: {timestamp:tt} {_}' -> '(.+?): (?P<timestamp>(\\d{1,2}:\\d{1,2}(:\\d{1,2}(\\.\\d+)?)?)?(\\s+[AP]M)?(\\s+[-+]\\d\\d?:?\\d\\d)?) (.+?)'
::= Verbose mode (DEBUG). =::
DEBUG:asyncio:Using selector: EpollSelector
DEBUG:jhack:Fetching status with: 'juju status --relations -m testos'
DEBUG:jhack:Fetching status with: 'juju status --relations -m testos --format json'
DEBUG:jhack:Fetching status with: 'juju status --relations -m testos --format json'
ERROR:jhack./home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:juju status returned nothing!
DEBUG:jhack:Fetching status with: 'juju status --relations -m testos --format json'
ERROR:jhack./home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:juju status returned nothing!
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:1028 in            │
│ sync_show_relation                                                                               │
│                                                                                                  │
│   1025 │   - ``$ jhack utils show-relation my_app:peers`` - peer relation\n                      │
│   1026 │   - ``$ jhack utils show-relation my_app:foo cross_model_app:bar`` - CMRs\n             │
│   1027 │   """                                                                                   │
│ ❱ 1028 │   return _sync_show_relation(                                                           │
│   1029 │   │   endpoint1=endpoint1,                                                              │
│   1030 │   │   endpoint2=endpoint2,                                                              │
│   1031 │   │   n=n,                                                                              │
│                                                                                                  │
│ ╭────────────────── locals ───────────────────╮                                                  │
│ │               color = 'auto'                │                                                  │
│ │           endpoint1 = 'ntp:ntp-peers'       │                                                  │
│ │           endpoint2 = None                  │                                                  │
│ │              format = <Format.auto: 'auto'> │                                                  │
│ │ hide_empty_databags = False                 │                                                  │
│ │               model = 'testos'              │                                                  │
│ │                   n = None                  │                                                  │
│ │      show_juju_keys = False                 │                                                  │
│ │               watch = False                 │                                                  │
│ ╰─────────────────────────────────────────────╯                                                  │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:1067 in            │
│ _sync_show_relation                                                                              │
│                                                                                                  │
│   1064 │   while True:                                                                           │
│   1065 │   │   start = time.time()                                                               │
│   1066 │   │                                                                                     │
│ ❱ 1067 │   │   table = asyncio.run(                                                              │
│   1068 │   │   │   render_relation(                                                              │
│   1069 │   │   │   │   endpoint1,                                                                │
│   1070 │   │   │   │   endpoint2,                                                                │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │               color = 'auto'                                                                 │ │
│ │             Console = <class 'rich.console.Console'>                                         │ │
│ │             console = <console width=249 ColorSystem.TRUECOLOR>                              │ │
│ │           endpoint1 = 'ntp:ntp-peers'                                                        │ │
│ │           endpoint2 = None                                                                   │ │
│ │              format = <Format.auto: 'auto'>                                                  │ │
│ │ hide_empty_databags = False                                                                  │ │
│ │               model = 'testos'                                                               │ │
│ │                   n = None                                                                   │ │
│ │                rich = <module 'rich' from                                                    │ │
│ │                       '/home/gboutry/Documents/canonical/projects/jhack/venv/lib/python3.10… │ │
│ │      show_juju_keys = False                                                                  │ │
│ │               start = 1724161940.095359                                                      │ │
│ │               watch = False                                                                  │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /home/gboutry/.rye/py/cpython@3.10.13/install/lib/python3.10/asyncio/runners.py:44 in run        │
│                                                                                                  │
│   41 │   │   events.set_event_loop(loop)                                                         │
│   42 │   │   if debug is not None:                                                               │
│   43 │   │   │   loop.set_debug(debug)                                                           │
│ ❱ 44 │   │   return loop.run_until_complete(main)                                                │
│   45 │   finally:                                                                                │
│   46 │   │   try:                                                                                │
│   47 │   │   │   _cancel_all_tasks(loop)                                                         │
│                                                                                                  │
│ ╭──────────────────────────────── locals ────────────────────────────────╮                       │
│ │ debug = None                                                           │                       │
│ │  loop = <_UnixSelectorEventLoop running=False closed=True debug=False> │                       │
│ │  main = <coroutine object render_relation at 0x754d8492f290>           │                       │
│ ╰────────────────────────────────────────────────────────────────────────╯                       │
│                                                                                                  │
│ /home/gboutry/.rye/py/cpython@3.10.13/install/lib/python3.10/asyncio/base_events.py:649 in       │
│ run_until_complete                                                                               │
│                                                                                                  │
│    646 │   │   if not future.done():                                                             │
│    647 │   │   │   raise RuntimeError('Event loop stopped before Future completed.')             │
│    648 │   │                                                                                     │
│ ❱  649 │   │   return future.result()                                                            │
│    650 │                                                                                         │
│    651 │   def stop(self):                                                                       │
│    652 │   │   """Stop running the event loop.                                                   │
│                                                                                                  │
│ ╭─────────────────────────────────────────── locals ───────────────────────────────────────────╮ │
│ │   future = <Task finished name='Task-1' coro=<render_relation() done, defined at             │ │
│ │            /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:79… │ │
│ │            exception=KeyError('applications')>                                               │ │
│ │ new_task = True                                                                              │ │
│ │     self = <_UnixSelectorEventLoop running=False closed=True debug=False>                    │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:819 in             │
│ render_relation                                                                                  │
│                                                                                                  │
│    816 │   │   if endpoint1.app_name in saas or (endpoint2 and endpoint2.app_name in saas):      │
│    817 │   │   │   relation.raw_type = "cross_model"                                             │
│    818 │                                                                                         │
│ ❱  819 │   entities = _gather_entities(                                                          │
│    820 │   │   endpoint1,                                                                        │
│    821 │   │   endpoint2,                                                                        │
│    822 │   │   relation,                                                                         │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                 endpoint1 = 'ntp:ntp-peers'                    │                               │
│ │                 endpoint2 = None                               │                               │
│ │                    format = <Format.auto: 'auto'>              │                               │
│ │       hide_empty_databags = False                              │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                         n = None                               │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:770 in             │
│ _gather_entities                                                                                 │
│                                                                                                  │
│    767 ) -> Tuple[AppRelationData, ...]:                                                         │
│    768 │   if relation.type == RelationType.peer:                                                │
│    769 │   │   return (                                                                          │
│ ❱  770 │   │   │   get_peer_relation_data(                                                       │
│    771 │   │   │   │   endpoint=endpoint1,                                                       │
│    772 │   │   │   │   include_default_juju_keys=include_default_juju_keys,                      │
│    773 │   │   │   │   model=model,                                                              │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                 endpoint1 = 'ntp:ntp-peers'                    │                               │
│ │                 endpoint2 = None                               │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:551 in             │
│ get_peer_relation_data                                                                           │
│                                                                                                  │
│    548 │   include_default_juju_keys: bool = False,                                              │
│    549 │   model: str = None,                                                                    │
│    550 ) -> AppRelationData:                                                                     │
│ ❱  551 │   return get_content(                                                                   │
│    552 │   │   endpoint,                                                                         │
│    553 │   │   endpoint,                                                                         │
│    554 │   │   relation,                                                                         │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │                  endpoint = 'ntp:ntp-peers'                    │                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:379 in get_content │
│                                                                                                  │
│    376 │   # so even though we need 'any' remote unit name, we still need to query the status    │
│    377 │   # to find out what units there are.                                                   │
│    378 │   status = _juju_status(model=model, json=True)                                         │
│ ❱  379 │   units, meta = get_units_and_meta(obj, model)                                          │
│    380 │                                                                                         │
│    381 │   if other_model != model:                                                              │
│    382 │   │   logger.info(f"other app is in model {other_model!r}. Pulling status...")          │
│                                                                                                  │
│ ╭──────────────────────────── locals ────────────────────────────╮                               │
│ │ include_default_juju_keys = False                              │                               │
│ │                     model = 'testos'                           │                               │
│ │                       obj = 'ntp:ntp-peers'                    │                               │
│ │               other_model = None                               │                               │
│ │                 other_obj = 'ntp:ntp-peers'                    │                               │
│ │                  relation = Relation(                          │                               │
│ │                             │   provider='ntp',                │                               │
│ │                             │   provider_endpoint='ntp-peers', │                               │
│ │                             │   requirer='ntp',                │                               │
│ │                             │   requirer_endpoint='ntp-peers', │                               │
│ │                             │   interface='ntp',               │                               │
│ │                             │   raw_type='peer'                │                               │
│ │                             )                                  │                               │
│ │                    status = {}                                 │                               │
│ ╰────────────────────────────────────────────────────────────────╯                               │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:358 in             │
│ get_units_and_meta                                                                               │
│                                                                                                  │
│    355 │   model: str = None,                                                                    │
│    356 ):                                                                                        │
│    357 │   """Get app name and unit count from url; url is either `app_name/0` or `app_name`.""  │
│ ❱  358 │   meta = get_metadata_from_status(endpoint, model=model)                                │
│    359 │   if endpoint.unit_id is not None:                                                      │
│    360 │   │   units = (int(endpoint.unit_id),)                                                  │
│    361 │   else:                                                                                 │
│                                                                                                  │
│ ╭────────── locals ──────────╮                                                                   │
│ │ endpoint = 'ntp:ntp-peers' │                                                                   │
│ │    model = 'testos'        │                                                                   │
│ ╰────────────────────────────╯                                                                   │
│                                                                                                  │
│ /home/gboutry/Documents/canonical/projects/jhack/jhack/utils/show_relation.py:309 in             │
│ get_metadata_from_status                                                                         │
│                                                                                                  │
│    306 ):                                                                                        │
│    307 │   status = _juju_status(model=model, json=True)                                         │
│    308 │   # machine status json output apparently has no 'scale'... -_-                         │
│ ❱  309 │   app_status = status["applications"][endpoint.app_name]                                │
│    310 │   if app_status.get("subordinate-to"):                                                  │
│    311 │   │   units = {}                                                                        │
│    312 │   │   # todo: need to scavenge unit names from OTHER units' .subordinates field         │
│                                                                                                  │
│ ╭────────── locals ──────────╮                                                                   │
│ │ endpoint = 'ntp:ntp-peers' │                                                                   │
│ │    model = 'testos'        │                                                                   │
│ │   status = {}              │                                                                   │
│ ╰────────────────────────────╯                                                                   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
KeyError: 'applications'

(I trust you, but still read the code before haha)

gboutry commented 2 months ago

Ok, after some more testing, I had no errors in the status cli, until I added --format json

juju status --relations -m testos --format json
provided relations option is always enabled in non tabular formats
{}
ERROR cannot process storage instances: cannot convert storage details for storage-database-0: filesystem for storage instance "database/0" not found (not found)

This seems to be the root issue.

PietroPasotti commented 2 months ago

huh that sounds like a juju bug?