/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos-ctl

  • Committer: Teddy Hogeborn
  • Date: 2019-03-15 19:59:49 UTC
  • mto: This revision was merged to the branch mainline in revision 382.
  • Revision ID: teddy@recompile.se-20190315195949-km03h309lrqwl3ym
mandos-ctl: Bug fix: always shutdown logging.

* mandos-ctl: Shutdown logging at application exit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
93
93
    if options.debug:
94
94
        log.setLevel(logging.DEBUG)
95
95
 
96
 
    bus = dbus.SystemBus()
97
 
 
98
 
    mandos_dbus_object = get_mandos_dbus_object(bus)
99
 
 
100
 
    mandos_serv = dbus.Interface(
101
 
        mandos_dbus_object, dbus_interface=server_dbus_interface)
 
96
    try:
 
97
        bus = dbus.SystemBus()
 
98
        log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
 
99
                  dbus_busname, server_dbus_path)
 
100
        mandos_dbus_objc = bus.get_object(dbus_busname,
 
101
                                          server_dbus_path)
 
102
    except dbus.exceptions.DBusException:
 
103
        log.critical("Could not connect to Mandos server")
 
104
        sys.exit(1)
 
105
 
 
106
    mandos_serv = dbus.Interface(mandos_dbus_objc,
 
107
                                 dbus_interface=server_dbus_interface)
102
108
    mandos_serv_object_manager = dbus.Interface(
103
 
        mandos_dbus_object, dbus_interface=dbus.OBJECT_MANAGER_IFACE)
104
 
 
105
 
    managed_objects = get_managed_objects(mandos_serv_object_manager)
106
 
 
107
 
    all_clients = {}
108
 
    for path, ifs_and_props in managed_objects.items():
109
 
        try:
110
 
            all_clients[path] = ifs_and_props[client_dbus_interface]
111
 
        except KeyError:
112
 
            pass
113
 
 
114
 
    # Compile dict of (clientpath: properties) to process
 
109
        mandos_dbus_objc, dbus_interface=dbus.OBJECT_MANAGER_IFACE)
 
110
 
 
111
    try:
 
112
        log.debug("D-Bus: %s:%s:%s.GetManagedObjects()", dbus_busname,
 
113
                  server_dbus_path, dbus.OBJECT_MANAGER_IFACE)
 
114
        with SilenceLogger("dbus.proxies"):
 
115
            all_clients = {path: ifs_and_props[client_dbus_interface]
 
116
                              for path, ifs_and_props in
 
117
                              mandos_serv_object_manager
 
118
                              .GetManagedObjects().items()
 
119
                              if client_dbus_interface in ifs_and_props}
 
120
    except dbus.exceptions.DBusException as e:
 
121
        log.critical("Failed to access Mandos server through D-Bus:"
 
122
                     "\n%s", e)
 
123
        sys.exit(1)
 
124
 
 
125
    # Compile dict of (clients: properties) to process
 
126
    clients = {}
 
127
 
115
128
    if not clientnames:
116
129
        clients = all_clients
117
130
    else:
118
 
        clients = {}
119
131
        for name in clientnames:
120
132
            for objpath, properties in all_clients.items():
121
133
                if properties["Name"] == name:
424
436
        options.remove = True
425
437
 
426
438
 
427
 
def get_mandos_dbus_object(bus):
428
 
    log.debug("D-Bus: Connect to: (busname=%r, path=%r)",
429
 
              dbus_busname, server_dbus_path)
430
 
    with if_dbus_exception_log_with_exception_and_exit(
431
 
            "Could not connect to Mandos server: %s"):
432
 
        mandos_dbus_object = bus.get_object(dbus_busname,
433
 
                                            server_dbus_path)
434
 
    return mandos_dbus_object
435
 
 
436
 
 
437
 
@contextlib.contextmanager
438
 
def if_dbus_exception_log_with_exception_and_exit(*args, **kwargs):
439
 
    try:
440
 
        yield
441
 
    except dbus.exceptions.DBusException as e:
442
 
        log.critical(*(args + (e,)), **kwargs)
443
 
        sys.exit(1)
444
 
 
445
 
 
446
 
def get_managed_objects(object_manager):
447
 
    log.debug("D-Bus: %s:%s:%s.GetManagedObjects()", dbus_busname,
448
 
              server_dbus_path, dbus.OBJECT_MANAGER_IFACE)
449
 
    with if_dbus_exception_log_with_exception_and_exit(
450
 
            "Failed to access Mandos server through D-Bus:\n%s"):
451
 
        with SilenceLogger("dbus.proxies"):
452
 
            managed_objects = object_manager.GetManagedObjects()
453
 
    return managed_objects
454
 
 
455
 
 
456
439
class SilenceLogger(object):
457
440
    "Simple context manager to silence a particular logger"
458
441
    def __init__(self, loggername):
1005
988
                self.check_option_syntax(options)
1006
989
 
1007
990
 
1008
 
class Test_get_mandos_dbus_object(unittest.TestCase):
1009
 
    def test_calls_and_returns_get_object_on_bus(self):
1010
 
        class MockBus(object):
1011
 
            called = False
1012
 
            def get_object(mockbus_self, busname, dbus_path):
1013
 
                # Note that "self" is still the testcase instance,
1014
 
                # this MockBus instance is in "mockbus_self".
1015
 
                self.assertEqual(busname, dbus_busname)
1016
 
                self.assertEqual(dbus_path, server_dbus_path)
1017
 
                mockbus_self.called = True
1018
 
                return mockbus_self
1019
 
 
1020
 
        mockbus = get_mandos_dbus_object(bus=MockBus())
1021
 
        self.assertIsInstance(mockbus, MockBus)
1022
 
        self.assertTrue(mockbus.called)
1023
 
 
1024
 
    def test_logs_and_exits_on_dbus_error(self):
1025
 
        class MockBusFailing(object):
1026
 
            def get_object(self, busname, dbus_path):
1027
 
                raise dbus.exceptions.DBusException("Test")
1028
 
 
1029
 
        # assertLogs only exists in Python 3.4
1030
 
        if hasattr(self, "assertLogs"):
1031
 
            with self.assertLogs(log, logging.CRITICAL):
1032
 
                with self.assertRaises(SystemExit) as e:
1033
 
                    bus = get_mandos_dbus_object(bus=MockBus())
1034
 
        else:
1035
 
            critical_filter = self.CriticalFilter()
1036
 
            log.addFilter(critical_filter)
1037
 
            try:
1038
 
                with self.assertRaises(SystemExit) as e:
1039
 
                    get_mandos_dbus_object(bus=MockBusFailing())
1040
 
            finally:
1041
 
                log.removeFilter(critical_filter)
1042
 
            self.assertTrue(critical_filter.found)
1043
 
        if isinstance(e.exception.code, int):
1044
 
            self.assertNotEqual(e.exception.code, 0)
1045
 
        else:
1046
 
            self.assertIsNotNone(e.exception.code)
1047
 
 
1048
 
    class CriticalFilter(logging.Filter):
1049
 
        """Don't show, but register, critical messages"""
1050
 
        found = False
1051
 
        def filter(self, record):
1052
 
            is_critical = record.levelno >= logging.CRITICAL
1053
 
            self.found = is_critical or self.found
1054
 
            return not is_critical
1055
 
 
1056
 
 
1057
 
class Test_get_managed_objects(unittest.TestCase):
1058
 
    def test_calls_and_returns_GetManagedObjects(self):
1059
 
        managed_objects = {"/clients/foo": { "Name": "foo"}}
1060
 
        class MockObjectManager(object):
1061
 
            @staticmethod
1062
 
            def GetManagedObjects():
1063
 
                return managed_objects
1064
 
        retval = get_managed_objects(MockObjectManager())
1065
 
        self.assertDictEqual(managed_objects, retval)
1066
 
 
1067
 
    def test_logs_and_exits_on_dbus_error(self):
1068
 
        class MockObjectManagerFailing(object):
1069
 
            @staticmethod
1070
 
            def GetManagedObjects():
1071
 
                raise dbus.exceptions.DBusException("Test")
1072
 
 
1073
 
        if hasattr(self, "assertLogs"):
1074
 
            with self.assertLogs(log, logging.CRITICAL):
1075
 
                with self.assertRaises(SystemExit):
1076
 
                    get_managed_objects(MockObjectManagerFailing())
1077
 
        else:
1078
 
            critical_filter = self.CriticalFilter()
1079
 
            log.addFilter(critical_filter)
1080
 
            try:
1081
 
                with self.assertRaises(SystemExit) as e:
1082
 
                    get_managed_objects(MockObjectManagerFailing())
1083
 
            finally:
1084
 
                log.removeFilter(critical_filter)
1085
 
            self.assertTrue(critical_filter.found)
1086
 
        if isinstance(e.exception.code, int):
1087
 
            self.assertNotEqual(e.exception.code, 0)
1088
 
        else:
1089
 
            self.assertIsNotNone(e.exception.code)
1090
 
 
1091
 
    class CriticalFilter(logging.Filter):
1092
 
        """Don't show, but register, critical messages"""
1093
 
        found = False
1094
 
        def filter(self, record):
1095
 
            is_critical = record.levelno >= logging.CRITICAL
1096
 
            self.found = is_critical or self.found
1097
 
            return not is_critical
1098
 
 
1099
 
 
1100
991
class Test_SilenceLogger(unittest.TestCase):
1101
992
    loggername = "mandos-ctl.Test_SilenceLogger"
1102
993
    log = logging.getLogger(loggername)