def test_unique_kvp_key(self): reporter = HyperVKvpReportingHandler(kvp_file_path=self.tmp_file_path) evt1 = events.ReportingEvent("event_type", 'event_message', "event_description") reporter.publish_event(evt1) evt2 = events.ReportingEvent("event_type", 'event_message', "event_description", timestamp=evt1.timestamp + 1) reporter.publish_event(evt2) reporter.q.join() kvps = list(reporter._iterate_kvps(0)) self.assertEqual(2, len(kvps)) self.assertNotEqual(kvps[0]["key"], kvps[1]["key"], "duplicate keys for KVP entries")
def report_diagnostic_event(str): """Report a diagnostic event""" evt = events.ReportingEvent(DIAGNOSTIC_EVENT_TYPE, 'diagnostic message', str, events.DEFAULT_EVENT_ORIGIN) events.report_event(evt) # return the event for unit testing purpose return evt
def test_events_with_higher_incarnation_not_over_written(self): reporter = HyperVKvpReportingHandler(kvp_file_path=self.tmp_file_path) self.assertEqual(0, len(list(reporter._iterate_kvps(0)))) reporter.publish_event( events.ReportingEvent('foo', 'name1', 'description')) reporter.publish_event( events.ReportingEvent('foo', 'name2', 'description')) reporter.q.join() self.assertEqual(2, len(list(reporter._iterate_kvps(0)))) reporter3 = HyperVKvpReportingHandler(kvp_file_path=self.tmp_file_path) reporter3.incarnation_no = reporter.incarnation_no - 1 reporter3.publish_event( events.ReportingEvent('foo', 'name3', 'description')) reporter3.q.join() self.assertEqual(3, len(list(reporter3._iterate_kvps(0))))
def test_appropriate_logger_used(self, getLogger): event_type, event_name = 'test_type', 'test_name' event = events.ReportingEvent(event_type, event_name, 'description') reporting.handlers.LogHandler().publish_event(event) self.assertEqual( [mock.call( 'cloudinit.reporting.{0}.{1}'.format(event_type, event_name))], getLogger.call_args_list)
def test_appropriate_logger_used(self, getLogger): event_type, event_name = "test_type", "test_name" event = events.ReportingEvent(event_type, event_name, "description") reporting.handlers.LogHandler().publish_event(event) self.assertEqual( [ mock.call("cloudinit.reporting.{0}.{1}".format( event_type, event_name)) ], getLogger.call_args_list, )
def report_diagnostic_event( msg: str, *, logger_func=None) -> events.ReportingEvent: """Report a diagnostic event""" if callable(logger_func): logger_func(msg) evt = events.ReportingEvent( DIAGNOSTIC_EVENT_TYPE, 'diagnostic message', msg, events.DEFAULT_EVENT_ORIGIN) events.report_event(evt, excluded_handler_types={"log"}) # return the event for unit testing purpose return evt
def test_as_dict(self): event_type, name, desc = 'test_type', 'test_name', 'test_desc' event = events.ReportingEvent(event_type, name, desc) expected = {'event_type': event_type, 'name': name, 'description': desc, 'origin': 'cloudinit'} # allow for timestamp to differ, but must be present as_dict = event.as_dict() self.assertIn('timestamp', as_dict) del as_dict['timestamp'] self.assertEqual(expected, as_dict)
def test_events_are_over_written(self): reporter = handlers.HyperVKvpReportingHandler( kvp_file_path=self.tmp_file_path) self.assertEqual(0, len(list(reporter._iterate_kvps(0)))) reporter.publish_event( events.ReportingEvent('foo', 'name1', 'description')) reporter.publish_event( events.ReportingEvent('foo', 'name2', 'description')) reporter.q.join() self.assertEqual(2, len(list(reporter._iterate_kvps(0)))) reporter2 = handlers.HyperVKvpReportingHandler( kvp_file_path=self.tmp_file_path) reporter2.incarnation_no = reporter.incarnation_no + 1 reporter2.publish_event( events.ReportingEvent('foo', 'name3', 'description')) reporter2.q.join() self.assertEqual(2, len(list(reporter2._iterate_kvps(0))))
def report_compressed_event(event_name, event_content): """Report a compressed event""" compressed_data = base64.encodebytes(zlib.compress(event_content)) event_data = {"encoding": "gz+b64", "data": compressed_data.decode('ascii')} evt = events.ReportingEvent( COMPRESSED_EVENT_TYPE, event_name, json.dumps(event_data), events.DEFAULT_EVENT_ORIGIN) events.report_event(evt, excluded_handler_types={"log", "print", "webhook"}) # return the event for unit testing purpose return evt
def test_event_type_can_be_filtered(self): reporter = handlers.HyperVKvpReportingHandler( kvp_file_path=self.tmp_file_path, event_types=['foo', 'bar']) reporter.publish_event( events.ReportingEvent('foo', 'name', 'description')) reporter.publish_event( events.ReportingEvent('some_other', 'name', 'description3')) reporter.q.join() kvps = list(reporter._iterate_kvps(0)) self.assertEqual(1, len(kvps)) reporter.publish_event( events.ReportingEvent('bar', 'name', 'description2')) reporter.q.join() kvps = list(reporter._iterate_kvps(0)) self.assertEqual(2, len(kvps)) self.assertIn('foo', kvps[0]['key']) self.assertIn('bar', kvps[1]['key']) self.assertNotIn('some_other', kvps[0]['key']) self.assertNotIn('some_other', kvps[1]['key'])
def get_system_info(): """Collect and report system information""" info = util.system_info() evt = events.ReportingEvent( SYSTEMINFO_EVENT_TYPE, 'system information', "cloudinit_version=%s, kernel_version=%s, variant=%s, " "distro_name=%s, distro_version=%s, flavor=%s, " "python_version=%s" % (version.version_string(), info['release'], info['variant'], info['dist'][0], info['dist'][1], info['dist'][2], info['python']), events.DEFAULT_EVENT_ORIGIN) events.report_event(evt) # return the event for unit testing purpose return evt
def test_as_dict(self): event_type, name, desc = "test_type", "test_name", "test_desc" event = events.ReportingEvent(event_type, name, desc) expected = { "event_type": event_type, "name": name, "description": desc, "origin": "cloudinit", } # allow for timestamp to differ, but must be present as_dict = event.as_dict() self.assertIn("timestamp", as_dict) del as_dict["timestamp"] self.assertEqual(expected, as_dict)
def get_boot_telemetry(): """Report timestamps related to kernel initialization and systemd activation of cloud-init""" if not distros.uses_systemd(): raise RuntimeError("distro not using systemd, skipping boot telemetry") LOG.debug("Collecting boot telemetry") try: kernel_start = float(time.time()) - float(util.uptime()) except ValueError: raise RuntimeError("Failed to determine kernel start timestamp") try: out, _ = util.subp( ['/bin/systemctl', 'show', '-p', 'UserspaceTimestampMonotonic'], capture=True) tsm = None if out and '=' in out: tsm = out.split("=")[1] if not tsm: raise RuntimeError("Failed to parse " "UserspaceTimestampMonotonic from systemd") user_start = kernel_start + (float(tsm) / 1000000) except util.ProcessExecutionError as e: raise RuntimeError("Failed to get UserspaceTimestampMonotonic: %s" % e) except ValueError as e: raise RuntimeError("Failed to parse " "UserspaceTimestampMonotonic from systemd: %s" % e) try: out, _ = util.subp([ '/bin/systemctl', 'show', 'cloud-init-local', '-p', 'InactiveExitTimestampMonotonic' ], capture=True) tsm = None if out and '=' in out: tsm = out.split("=")[1] if not tsm: raise RuntimeError("Failed to parse " "InactiveExitTimestampMonotonic from systemd") cloudinit_activation = kernel_start + (float(tsm) / 1000000) except util.ProcessExecutionError as e: raise RuntimeError("Failed to get InactiveExitTimestampMonotonic: %s" % e) except ValueError as e: raise RuntimeError("Failed to parse " "InactiveExitTimestampMonotonic from systemd: %s" % e) evt = events.ReportingEvent( BOOT_EVENT_TYPE, 'boot-telemetry', "kernel_start=%s user_start=%s cloudinit_activation=%s" % (datetime.utcfromtimestamp(kernel_start).isoformat() + 'Z', datetime.utcfromtimestamp(user_start).isoformat() + 'Z', datetime.utcfromtimestamp(cloudinit_activation).isoformat() + 'Z'), events.DEFAULT_EVENT_ORIGIN) events.report_event(evt) # return the event for unit testing purpose return evt
def test_as_string(self): event_type, name, description = 'test_type', 'test_name', 'test_desc' event = events.ReportingEvent(event_type, name, description) expected_string_representation = ': '.join( [event_type, name, description]) self.assertEqual(expected_string_representation, event.as_string())
def test_log_message_uses_event_as_string(self, getLogger): event = events.ReportingEvent('type', 'name', 'description') reporting.handlers.LogHandler(level="INFO").publish_event(event) self.assertIn(event.as_string(), getLogger.return_value.log.call_args[0][1])
def test_single_log_message_at_info_published(self, getLogger): event = events.ReportingEvent('type', 'name', 'description') reporting.handlers.LogHandler().publish_event(event) self.assertEqual(1, getLogger.return_value.log.call_count)