diff --git a/cloudinit/analyze/dump.py b/cloudinit/analyze/dump.py index 60a2fd9b28d8..88f6c100d757 100644 --- a/cloudinit/analyze/dump.py +++ b/cloudinit/analyze/dump.py @@ -50,19 +50,26 @@ def parse_timestamp(timestampstr): return float(timestamp) +def has_gnu_date(): + """GNU date includes a string containing the word GNU in it in + help output. Posix date does not. Use this to indicate on Linux + systems without GNU date that the extended parsing is not + available. + """ + return "GNU" in subp.subp(["date", "--help"]).stdout def parse_timestamp_from_date(timestampstr): - cmd = "date" - if not util.is_Linux(): - if subp.which("gdate"): - cmd = "gdate" - else: - raise ValueError( - f"Unable to parse timestamp without GNU date: [{timestampstr}]" - ) - out, _ = subp.subp([cmd, "+%s.%3N", "-d", timestampstr]) - timestamp = out.strip() - return float(timestamp) + if not util.is_Linux() and subp.which("gdate"): + date = "gdate" + elif has_gnu_date(): + date = "date" + else: + raise ValueError( + f"Unable to parse timestamp without GNU date: [{timestampstr}]" + ) + return float( + subp.subp([date, "+%s.%3N", "-d", timestampstr]).stdout.strip() + ) def parse_ci_logline(line): diff --git a/tests/unittests/analyze/test_dump.py b/tests/unittests/analyze/test_dump.py index 3fb0046aa598..82c44720976c 100644 --- a/tests/unittests/analyze/test_dump.py +++ b/tests/unittests/analyze/test_dump.py @@ -9,10 +9,10 @@ dump_events, parse_ci_logline, parse_timestamp, + has_gnu_date, ) -from cloudinit.subp import which -from cloudinit.util import is_Linux, write_file -from tests.unittests.helpers import mock, skipIf +from cloudinit.util import write_file +from tests.unittests.helpers import mock class TestParseTimestamp: @@ -43,11 +43,6 @@ def test_parse_timestamp_handles_journalctl_format_adding_year(self): dt = datetime.strptime(journal_stamp + " " + str(year), journal_fmt) assert float(dt.strftime("%s.%f")) == parse_timestamp(journal_stamp) - @skipIf(not which("date"), "'date' command not available.") - @skipIf( - not is_Linux() and not which("gdate"), - "'GNU date' command not available.", - ) @pytest.mark.allow_subp_for("date", "gdate") def test_parse_unexpected_timestamp_format_with_date_command(self): """Dump sends unexpected timestamp formats to date for processing.""" @@ -57,7 +52,11 @@ def test_parse_unexpected_timestamp_format_with_date_command(self): year = datetime.now().year dt = datetime.strptime(new_stamp + " " + str(year), new_fmt) - assert float(dt.strftime("%s.%f")) == parse_timestamp(new_stamp) + if has_gnu_date(): + assert float(dt.strftime("%s.%f")) == parse_timestamp(new_stamp) + else: + with pytest.raises(ValueError): + parse_timestamp(new_stamp) class TestParseCILogLine: