~ddellav/charms/trusty/glance/upgrade-action

« back to all changes in this revision

Viewing changes to tests/charmhelpers/contrib/amulet/utils.py

  • Committer: james.page at ubuntu
  • Date: 2015-07-07 14:02:07 UTC
  • mfrom: (121.1.5 glance)
  • Revision ID: james.page@ubuntu.com-20150707140207-k0wvswzi7qq6e94t
Update amulet tests for Kilo, prep for wily. Sync hooks/charmhelpers; Sync tests/charmhelpers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
185
185
        for k in expected.keys():
186
186
            if not config.has_option(section, k):
187
187
                return "section [{}] is missing option {}".format(section, k)
188
 
            if config.get(section, k) != expected[k]:
189
 
                return "section [{}] {}:{} != expected {}:{}".format(
190
 
                       section, k, config.get(section, k), k, expected[k])
191
 
        return None
 
188
 
 
189
            actual = config.get(section, k)
 
190
            v = expected[k]
 
191
            if (isinstance(v, six.string_types) or
 
192
                    isinstance(v, bool) or
 
193
                    isinstance(v, six.integer_types)):
 
194
                # handle explicit values
 
195
                if actual != v:
 
196
                    return "section [{}] {}:{} != expected {}:{}".format(
 
197
                           section, k, actual, k, expected[k])
 
198
            else:
 
199
                # handle not_null, valid_ip boolean comparison methods, etc.
 
200
                if v(actual):
 
201
                    return None
 
202
                else:
 
203
                    return "section [{}] {}:{} != expected {}:{}".format(
 
204
                           section, k, actual, k, expected[k])
192
205
 
193
206
    def _validate_dict_data(self, expected, actual):
194
207
        """Validate dictionary data.
406
419
        """Convert a relative file path to a file URL."""
407
420
        _abs_path = os.path.abspath(file_rel_path)
408
421
        return urlparse.urlparse(_abs_path, scheme='file').geturl()
 
422
 
 
423
    def check_commands_on_units(self, commands, sentry_units):
 
424
        """Check that all commands in a list exit zero on all
 
425
        sentry units in a list.
 
426
 
 
427
        :param commands:  list of bash commands
 
428
        :param sentry_units:  list of sentry unit pointers
 
429
        :returns: None if successful; Failure message otherwise
 
430
        """
 
431
        self.log.debug('Checking exit codes for {} commands on {} '
 
432
                       'sentry units...'.format(len(commands),
 
433
                                                len(sentry_units)))
 
434
        for sentry_unit in sentry_units:
 
435
            for cmd in commands:
 
436
                output, code = sentry_unit.run(cmd)
 
437
                if code == 0:
 
438
                    msg = ('{} `{}` returned {} '
 
439
                           '(OK)'.format(sentry_unit.info['unit_name'],
 
440
                                         cmd, code))
 
441
                    self.log.debug(msg)
 
442
                else:
 
443
                    msg = ('{} `{}` returned {} '
 
444
                           '{}'.format(sentry_unit.info['unit_name'],
 
445
                                       cmd, code, output))
 
446
                    return msg
 
447
        return None
 
448
 
 
449
    def get_process_id_list(self, sentry_unit, process_name):
 
450
        """Get a list of process ID(s) from a single sentry juju unit
 
451
        for a single process name.
 
452
 
 
453
        :param sentry_unit: Pointer to amulet sentry instance (juju unit)
 
454
        :param process_name: Process name
 
455
        :returns: List of process IDs
 
456
        """
 
457
        cmd = 'pidof {}'.format(process_name)
 
458
        output, code = sentry_unit.run(cmd)
 
459
        if code != 0:
 
460
            msg = ('{} `{}` returned {} '
 
461
                   '{}'.format(sentry_unit.info['unit_name'],
 
462
                               cmd, code, output))
 
463
            raise RuntimeError(msg)
 
464
        return str(output).split()
 
465
 
 
466
    def get_unit_process_ids(self, unit_processes):
 
467
        """Construct a dict containing unit sentries, process names, and
 
468
        process IDs."""
 
469
        pid_dict = {}
 
470
        for sentry_unit, process_list in unit_processes.iteritems():
 
471
            pid_dict[sentry_unit] = {}
 
472
            for process in process_list:
 
473
                pids = self.get_process_id_list(sentry_unit, process)
 
474
                pid_dict[sentry_unit].update({process: pids})
 
475
        return pid_dict
 
476
 
 
477
    def validate_unit_process_ids(self, expected, actual):
 
478
        """Validate process id quantities for services on units."""
 
479
        self.log.debug('Checking units for running processes...')
 
480
        self.log.debug('Expected PIDs: {}'.format(expected))
 
481
        self.log.debug('Actual PIDs: {}'.format(actual))
 
482
 
 
483
        if len(actual) != len(expected):
 
484
            msg = ('Unit count mismatch.  expected, actual: {}, '
 
485
                   '{} '.format(len(expected), len(actual)))
 
486
            return msg
 
487
 
 
488
        for (e_sentry, e_proc_names) in expected.iteritems():
 
489
            e_sentry_name = e_sentry.info['unit_name']
 
490
            if e_sentry in actual.keys():
 
491
                a_proc_names = actual[e_sentry]
 
492
            else:
 
493
                msg = ('Expected sentry ({}) not found in actual dict data.'
 
494
                       '{}'.format(e_sentry_name, e_sentry))
 
495
                return msg
 
496
 
 
497
            if len(e_proc_names.keys()) != len(a_proc_names.keys()):
 
498
                msg = ('Process name count mismatch.  expected, actual: {}, '
 
499
                       '{}'.format(len(expected), len(actual)))
 
500
                return msg
 
501
 
 
502
            for (e_proc_name, e_pids_length), (a_proc_name, a_pids) in \
 
503
                    zip(e_proc_names.items(), a_proc_names.items()):
 
504
                if e_proc_name != a_proc_name:
 
505
                    msg = ('Process name mismatch.  expected, actual: {}, '
 
506
                           '{}'.format(e_proc_name, a_proc_name))
 
507
                    return msg
 
508
 
 
509
                a_pids_length = len(a_pids)
 
510
                if e_pids_length != a_pids_length:
 
511
                    msg = ('PID count mismatch. {} ({}) expected, actual: {}, '
 
512
                           '{} ({})'.format(e_sentry_name,
 
513
                                            e_proc_name,
 
514
                                            e_pids_length,
 
515
                                            a_pids_length,
 
516
                                            a_pids))
 
517
                    return msg
 
518
                else:
 
519
                    msg = ('PID check OK: {} {} {}: '
 
520
                           '{}'.format(e_sentry_name,
 
521
                                       e_proc_name,
 
522
                                       e_pids_length,
 
523
                                       a_pids))
 
524
                    self.log.debug(msg)
 
525
        return None
 
526
 
 
527
    def validate_list_of_identical_dicts(self, list_of_dicts):
 
528
        """Check that all dicts within a list are identical."""
 
529
        hashes = []
 
530
        for _dict in list_of_dicts:
 
531
            hashes.append(hash(frozenset(_dict.items())))
 
532
 
 
533
        self.log.debug('Hashes: {}'.format(hashes))
 
534
        if len(set(hashes)) == 1:
 
535
            msg = 'Dicts within list are identical'
 
536
            self.log.debug(msg)
 
537
        else:
 
538
            msg = 'Dicts within list are not identical'
 
539
            return msg
 
540
 
 
541
        return None