~verterok/mojo/ignore-app-wait-support

« back to all changes in this revision

Viewing changes to mojo/juju/wait.py

  • Committer: Guillermo Gonzalez
  • Date: 2024-03-13 18:40:32 UTC
  • Revision ID: guillermo.gonzalez@canonical.com-20240313184032-549zs6qoksozi016
Add support to ignore-applications-wait (MOJO_WAIT_IGNORE_APPLICATIONS)

This allows to specify a comma separated list of application names to ignore in the wait

Show diffs side-by-side

added added

removed removed

Lines of Context:
117
117
    return {d['UnitId']: (d.get('ReturnCode', 0), d['Stdout']) for d in out}
118
118
 
119
119
 
120
 
def get_status():
 
120
def get_status(ignore_applications=None):
121
121
    # Older juju versions don't support --utc, so force UTC timestamps
122
122
    # using the environment variable.
123
123
    env = os.environ.copy()
125
125
    json_status = run_or_die([juju_exe(), 'status', '--format=json'], env=env)
126
126
    if json_status is None:
127
127
        return None
128
 
    return json.loads(json_status)
 
128
    status = json.loads(json_status)
 
129
    for to_ignore in ignore_applications or []:
 
130
        removed = status["applications"].pop(to_ignore)
 
131
        if removed:
 
132
            if "subordinate-to" in removed:
 
133
                # no machines to cleanup, the excluded/ignored application is a subordinate
 
134
                continue
 
135
            for unit, unit_data in removed['units'].items():
 
136
                # remove machines too
 
137
                status["machines"].pop(unit_data['machine'], None)
 
138
    return status
129
139
 
130
140
 
131
141
def get_log_tail(unit, timeout=None):
239
249
                'logging-config=juju=WARNING;unit=INFO'])
240
250
 
241
251
 
242
 
def wait(log=None, wait_for_workload=False, max_wait=None):
 
252
def wait(log=None, wait_for_workload=False, max_wait=None, ignore_applications=None):
243
253
    # Note that wait_for_workload is only useful as a workaround for
244
254
    # broken setups. It is impossible for a charm to report that it has
245
255
    # completed setup, because a charm has no information about units
263
273
        max_wait = float(max_wait)
264
274
 
265
275
    while True:
266
 
        status = get_status()
 
276
        status = get_status(ignore_applications)
267
277
        ready = True
268
278
 
269
279
        # If defined, fail if max_wait is exceeded
294
304
        agent_status = {}
295
305
        agent_version = {}
296
306
        unit_leadership = {}
297
 
        for _, service in services.items():
 
307
        for sname, service in services.items():
 
308
            if sname in ignore_applications:
 
309
                continue
298
310
            for uname, unit in service.get('units', {}).items():
 
311
                if uname.split('/')[0] in ignore_applications:
 
312
                    continue
299
313
                all_units.add(uname)
300
314
                unit_leadership[uname] = unit.get('leader', None)
301
315
                if 'agent-version' in unit:
319
333
                else:
320
334
                    ready_units[uname] = unit  # Schedule for sniffing.
321
335
                for subname, sub in unit.get('subordinates', {}).items():
 
336
                    if subname.split('/')[0] in ignore_applications:
 
337
                        continue
322
338
                    unit_leadership[subname] = sub.get('leader', None)
323
339
                    if ('workload-status' in sub and
324
340
                            'current' in sub['workload-status']):
359
375
                raise JujuWaitException(1)
360
376
 
361
377
        for uname, astatus in sorted(agent_status.items()):
 
378
            if uname.split('/')[0] in ignore_applications:
 
379
                logging.info("DEBUG: %s 0", uname)
 
380
                continue
362
381
            if not ('current' in astatus and 'since' in astatus):
363
382
                ready = False
364
383
                continue
377
396
            elif current != 'idle':
378
397
                logging.debug('{} juju agent status is {} since '
379
398
                              '{}Z'.format(uname, current, since))
 
399
                logging.info("DEBUG: %s marked as failed: %s 2", uname, current)
380
400
                ready = False
381
401
 
382
402
        # Log storage to compare with prev_logs.
385
405
        # Sniff logs of units that don't provide agent-status, if necessary.
386
406
        # This section can go when we drop support for Juju < 1.24.
387
407
        for uname, unit in sorted(ready_units.items()):
 
408
            if uname.split('/')[0] in ignore_applications:
 
409
                logging.info("DEBUG: %s 100", uname)
 
410
                continue
388
411
            dying = unit.get('life') in ('dying', 'dead')
389
412
            agent_state = unit.get('agent-state')
390
413
            agent_state_info = unit.get('agent-state-info')
397
420
                raise JujuWaitException(1)
398
421
            elif agent_state != 'started':
399
422
                logging.debug('{} is {}'.format(uname, agent_state))
 
423
                logging.info("DEBUG: %s marked as failed: %s 3", uname, agent_statet)
400
424
                ready = False
401
425
            elif ready:
402
426
                # We only start grabbing the logs once all the units