diff --git a/changelogs/fragments/8222-datetime.yml b/changelogs/fragments/8222-datetime.yml new file mode 100644 index 0000000000..00bf862186 --- /dev/null +++ b/changelogs/fragments/8222-datetime.yml @@ -0,0 +1,3 @@ +minor_changes: + - "Use offset-aware ``datetime.datetime`` objects (with timezone UTC) instead of offset-naive UTC timestamps, + which are deprecated in Python 3.12 (https://github.com/ansible-collections/community.general/pull/8222)." diff --git a/plugins/callback/loganalytics.py b/plugins/callback/loganalytics.py index fbcdc6f89f..ed7e47b2e2 100644 --- a/plugins/callback/loganalytics.py +++ b/plugins/callback/loganalytics.py @@ -59,13 +59,16 @@ import uuid import socket import getpass -from datetime import datetime from os.path import basename from ansible.module_utils.urls import open_url from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.plugins.callback import CallbackBase +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + class AzureLogAnalyticsSource(object): def __init__(self): @@ -93,7 +96,7 @@ class AzureLogAnalyticsSource(object): return "https://{0}.ods.opinsights.azure.com/api/logs?api-version=2016-04-01".format(workspace_id) def __rfc1123date(self): - return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT') + return now().strftime('%a, %d %b %Y %H:%M:%S GMT') def send_event(self, workspace_id, shared_key, state, result, runtime): if result._task_fields['args'].get('_ansible_check_mode') is True: @@ -167,7 +170,7 @@ class CallbackModule(CallbackBase): def _seconds_since_start(self, result): return ( - datetime.utcnow() - + now() - self.start_datetimes[result._task._uuid] ).total_seconds() @@ -185,10 +188,10 @@ class CallbackModule(CallbackBase): self.loganalytics.ansible_playbook = basename(playbook._file_name) def v2_playbook_on_task_start(self, task, is_conditional): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_playbook_on_handler_task_start(self, task): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_runner_on_ok(self, result, **kwargs): self.loganalytics.send_event( diff --git a/plugins/callback/logstash.py b/plugins/callback/logstash.py index 144e1f9915..f3725e465a 100644 --- a/plugins/callback/logstash.py +++ b/plugins/callback/logstash.py @@ -99,7 +99,6 @@ from ansible import context import socket import uuid import logging -from datetime import datetime try: import logstash @@ -109,6 +108,10 @@ except ImportError: from ansible.plugins.callback import CallbackBase +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + class CallbackModule(CallbackBase): @@ -126,7 +129,7 @@ class CallbackModule(CallbackBase): "pip install python-logstash for Python 2" "pip install python3-logstash for Python 3") - self.start_time = datetime.utcnow() + self.start_time = now() def _init_plugin(self): if not self.disabled: @@ -185,7 +188,7 @@ class CallbackModule(CallbackBase): self.logger.info("ansible start", extra=data) def v2_playbook_on_stats(self, stats): - end_time = datetime.utcnow() + end_time = now() runtime = end_time - self.start_time summarize_stat = {} for host in stats.processed.keys(): diff --git a/plugins/callback/splunk.py b/plugins/callback/splunk.py index d15547f44b..a3e401bc21 100644 --- a/plugins/callback/splunk.py +++ b/plugins/callback/splunk.py @@ -88,13 +88,16 @@ import uuid import socket import getpass -from datetime import datetime from os.path import basename from ansible.module_utils.urls import open_url from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.plugins.callback import CallbackBase +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + class SplunkHTTPCollectorSource(object): def __init__(self): @@ -134,7 +137,7 @@ class SplunkHTTPCollectorSource(object): else: time_format = '%Y-%m-%d %H:%M:%S +0000' - data['timestamp'] = datetime.utcnow().strftime(time_format) + data['timestamp'] = now().strftime(time_format) data['host'] = self.host data['ip_address'] = self.ip_address data['user'] = self.user @@ -181,7 +184,7 @@ class CallbackModule(CallbackBase): def _runtime(self, result): return ( - datetime.utcnow() - + now() - self.start_datetimes[result._task._uuid] ).total_seconds() @@ -220,10 +223,10 @@ class CallbackModule(CallbackBase): self.splunk.ansible_playbook = basename(playbook._file_name) def v2_playbook_on_task_start(self, task, is_conditional): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_playbook_on_handler_task_start(self, task): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_runner_on_ok(self, result, **kwargs): self.splunk.send_event( diff --git a/plugins/callback/sumologic.py b/plugins/callback/sumologic.py index 46ab3f0f7c..0304b9de52 100644 --- a/plugins/callback/sumologic.py +++ b/plugins/callback/sumologic.py @@ -46,13 +46,16 @@ import uuid import socket import getpass -from datetime import datetime from os.path import basename from ansible.module_utils.urls import open_url from ansible.parsing.ajson import AnsibleJSONEncoder from ansible.plugins.callback import CallbackBase +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + class SumologicHTTPCollectorSource(object): def __init__(self): @@ -84,8 +87,7 @@ class SumologicHTTPCollectorSource(object): data['uuid'] = result._task._uuid data['session'] = self.session data['status'] = state - data['timestamp'] = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S ' - '+0000') + data['timestamp'] = now().strftime('%Y-%m-%d %H:%M:%S +0000') data['host'] = self.host data['ip_address'] = self.ip_address data['user'] = self.user @@ -123,7 +125,7 @@ class CallbackModule(CallbackBase): def _runtime(self, result): return ( - datetime.utcnow() - + now() - self.start_datetimes[result._task._uuid] ).total_seconds() @@ -144,10 +146,10 @@ class CallbackModule(CallbackBase): self.sumologic.ansible_playbook = basename(playbook._file_name) def v2_playbook_on_task_start(self, task, is_conditional): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_playbook_on_handler_task_start(self, task): - self.start_datetimes[task._uuid] = datetime.utcnow() + self.start_datetimes[task._uuid] = now() def v2_runner_on_ok(self, result, **kwargs): self.sumologic.send_event( diff --git a/plugins/module_utils/datetime.py b/plugins/module_utils/datetime.py new file mode 100644 index 0000000000..c7899f68da --- /dev/null +++ b/plugins/module_utils/datetime.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2023 Felix Fontein +# Simplified BSD License (see LICENSES/BSD-2-Clause.txt or https://opensource.org/licenses/BSD-2-Clause) +# SPDX-License-Identifier: BSD-2-Clause + +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import datetime as _datetime +import sys + + +_USE_TIMEZONE = sys.version_info >= (3, 6) + + +def ensure_timezone_info(value): + if not _USE_TIMEZONE or value.tzinfo is not None: + return value + return value.astimezone(_datetime.timezone.utc) + + +def fromtimestamp(value): + if _USE_TIMEZONE: + return _datetime.fromtimestamp(value, tz=_datetime.timezone.utc) + return _datetime.utcfromtimestamp(value) + + +def now(): + if _USE_TIMEZONE: + return _datetime.datetime.now(tz=_datetime.timezone.utc) + return _datetime.datetime.utcnow() diff --git a/plugins/module_utils/scaleway.py b/plugins/module_utils/scaleway.py index 67b821103a..1310ba5602 100644 --- a/plugins/module_utils/scaleway.py +++ b/plugins/module_utils/scaleway.py @@ -17,6 +17,10 @@ from ansible.module_utils.basic import env_fallback, missing_required_lib from ansible.module_utils.urls import fetch_url from ansible.module_utils.six.moves.urllib.parse import urlencode +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + SCALEWAY_SECRET_IMP_ERR = None try: from passlib.hash import argon2 @@ -306,10 +310,10 @@ class Scaleway(object): # Prevent requesting the resource status too soon time.sleep(wait_sleep_time) - start = datetime.datetime.utcnow() + start = now() end = start + datetime.timedelta(seconds=wait_timeout) - while datetime.datetime.utcnow() < end: + while now() < end: self.module.debug("We are going to wait for the resource to finish its transition") state = self.fetch_state(resource) diff --git a/plugins/modules/cobbler_sync.py b/plugins/modules/cobbler_sync.py index 4ec87c96c7..27f57028be 100644 --- a/plugins/modules/cobbler_sync.py +++ b/plugins/modules/cobbler_sync.py @@ -75,13 +75,16 @@ RETURN = r''' # Default return values ''' -import datetime import ssl from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.six.moves import xmlrpc_client from ansible.module_utils.common.text.converters import to_text +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + def main(): module = AnsibleModule( @@ -110,7 +113,7 @@ def main(): changed=True, ) - start = datetime.datetime.utcnow() + start = now() ssl_context = None if not validate_certs: @@ -142,7 +145,7 @@ def main(): except Exception as e: module.fail_json(msg="Failed to sync Cobbler. {error}".format(error=to_text(e))) - elapsed = datetime.datetime.utcnow() - start + elapsed = now() - start module.exit_json(elapsed=elapsed.seconds, **result) diff --git a/plugins/modules/cobbler_system.py b/plugins/modules/cobbler_system.py index cecc02f717..a327ede84b 100644 --- a/plugins/modules/cobbler_system.py +++ b/plugins/modules/cobbler_system.py @@ -152,7 +152,6 @@ system: type: dict ''' -import datetime import ssl from ansible.module_utils.basic import AnsibleModule @@ -160,6 +159,10 @@ from ansible.module_utils.six import iteritems from ansible.module_utils.six.moves import xmlrpc_client from ansible.module_utils.common.text.converters import to_text +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + IFPROPS_MAPPING = dict( bondingopts='bonding_opts', bridgeopts='bridge_opts', @@ -232,7 +235,7 @@ def main(): changed=False, ) - start = datetime.datetime.utcnow() + start = now() ssl_context = None if not validate_certs: @@ -340,7 +343,7 @@ def main(): if module._diff: result['diff'] = dict(before=system, after=result['system']) - elapsed = datetime.datetime.utcnow() - start + elapsed = now() - start module.exit_json(elapsed=elapsed.seconds, **result) diff --git a/plugins/modules/github_key.py b/plugins/modules/github_key.py index fa3a0a01fa..a74ead9848 100644 --- a/plugins/modules/github_key.py +++ b/plugins/modules/github_key.py @@ -91,12 +91,17 @@ EXAMPLES = ''' pubkey: "{{ lookup('ansible.builtin.file', '/home/foo/.ssh/id_rsa.pub') }}" ''' +import datetime import json import re from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.urls import fetch_url +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + API_BASE = 'https://api.github.com' @@ -151,14 +156,13 @@ def get_all_keys(session): def create_key(session, name, pubkey, check_mode): if check_mode: - from datetime import datetime - now = datetime.utcnow() + now_t = now() return { 'id': 0, 'key': pubkey, 'title': name, 'url': 'http://example.com/CHECK_MODE_GITHUB_KEY', - 'created_at': datetime.strftime(now, '%Y-%m-%dT%H:%M:%SZ'), + 'created_at': datetime.strftime(now_t, '%Y-%m-%dT%H:%M:%SZ'), 'read_only': False, 'verified': False } diff --git a/plugins/modules/imc_rest.py b/plugins/modules/imc_rest.py index 113d341e89..7f5a5e0814 100644 --- a/plugins/modules/imc_rest.py +++ b/plugins/modules/imc_rest.py @@ -268,7 +268,6 @@ output: errorDescr="XML PARSING ERROR: Element 'computeRackUnit', attribute 'admin_Power': The attribute 'admin_Power' is not allowed.\n"/> ''' -import datetime import os import traceback @@ -292,6 +291,10 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib from ansible.module_utils.six.moves import zip_longest from ansible.module_utils.urls import fetch_url +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + def imc_response(module, rawoutput, rawinput=''): ''' Handle IMC returned data ''' @@ -375,14 +378,14 @@ def main(): else: module.fail_json(msg='Cannot find/access path:\n%s' % path) - start = datetime.datetime.utcnow() + start = now() # Perform login first url = '%s://%s/nuova' % (protocol, hostname) data = '' % (username, password) resp, auth = fetch_url(module, url, data=data, method='POST', timeout=timeout) if resp is None or auth['status'] != 200: - result['elapsed'] = (datetime.datetime.utcnow() - start).seconds + result['elapsed'] = (now() - start).seconds module.fail_json(msg='Task failed with error %(status)s: %(msg)s' % auth, **result) result.update(imc_response(module, resp.read())) @@ -415,7 +418,7 @@ def main(): # Perform actual request resp, info = fetch_url(module, url, data=data, method='POST', timeout=timeout) if resp is None or info['status'] != 200: - result['elapsed'] = (datetime.datetime.utcnow() - start).seconds + result['elapsed'] = (now() - start).seconds module.fail_json(msg='Task failed with error %(status)s: %(msg)s' % info, **result) # Merge results with previous results @@ -431,7 +434,7 @@ def main(): result['changed'] = ('modified' in results) # Report success - result['elapsed'] = (datetime.datetime.utcnow() - start).seconds + result['elapsed'] = (now() - start).seconds module.exit_json(**result) finally: logout(module, url, cookie, timeout) diff --git a/plugins/modules/pagerduty.py b/plugins/modules/pagerduty.py index 596c4f4da1..853bd6d797 100644 --- a/plugins/modules/pagerduty.py +++ b/plugins/modules/pagerduty.py @@ -151,6 +151,10 @@ import json from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.urls import fetch_url +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + class PagerDutyRequest(object): def __init__(self, module, name, user, token): @@ -206,9 +210,9 @@ class PagerDutyRequest(object): return [{'id': service, 'type': 'service_reference'}] def _compute_start_end_time(self, hours, minutes): - now = datetime.datetime.utcnow() - later = now + datetime.timedelta(hours=int(hours), minutes=int(minutes)) - start = now.strftime("%Y-%m-%dT%H:%M:%SZ") + now_t = now() + later = now_t + datetime.timedelta(hours=int(hours), minutes=int(minutes)) + start = now_t.strftime("%Y-%m-%dT%H:%M:%SZ") end = later.strftime("%Y-%m-%dT%H:%M:%SZ") return start, end diff --git a/plugins/modules/pagerduty_change.py b/plugins/modules/pagerduty_change.py index 1a1e50dcf7..acd31fb447 100644 --- a/plugins/modules/pagerduty_change.py +++ b/plugins/modules/pagerduty_change.py @@ -110,7 +110,10 @@ EXAMPLES = ''' from ansible.module_utils.urls import fetch_url from ansible.module_utils.basic import AnsibleModule -from datetime import datetime + +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) def main(): @@ -161,8 +164,7 @@ def main(): if module.params['environment']: custom_details['environment'] = module.params['environment'] - now = datetime.utcnow() - timestamp = now.strftime("%Y-%m-%dT%H:%M:%S.%fZ") + timestamp = now().strftime("%Y-%m-%dT%H:%M:%S.%fZ") payload = { 'summary': module.params['summary'], diff --git a/plugins/modules/scaleway_compute.py b/plugins/modules/scaleway_compute.py index 7f85bc6686..58a3215056 100644 --- a/plugins/modules/scaleway_compute.py +++ b/plugins/modules/scaleway_compute.py @@ -183,6 +183,7 @@ import datetime import time from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.general.plugins.module_utils.datetime import now from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway SCALEWAY_SERVER_STATES = ( @@ -235,9 +236,9 @@ def wait_to_complete_state_transition(compute_api, server, wait=None): wait_timeout = compute_api.module.params["wait_timeout"] wait_sleep_time = compute_api.module.params["wait_sleep_time"] - start = datetime.datetime.utcnow() + start = now() end = start + datetime.timedelta(seconds=wait_timeout) - while datetime.datetime.utcnow() < end: + while now() < end: compute_api.module.debug("We are going to wait for the server to finish its transition") if fetch_state(compute_api, server) not in SCALEWAY_TRANSITIONS_STATES: compute_api.module.debug("It seems that the server is not in transition anymore.") diff --git a/plugins/modules/scaleway_database_backup.py b/plugins/modules/scaleway_database_backup.py index 592ec0b7ff..1d0c17fb6d 100644 --- a/plugins/modules/scaleway_database_backup.py +++ b/plugins/modules/scaleway_database_backup.py @@ -170,6 +170,9 @@ import datetime import time from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) from ansible_collections.community.general.plugins.module_utils.scaleway import ( Scaleway, scaleway_argument_spec, @@ -189,9 +192,9 @@ def wait_to_complete_state_transition(module, account_api, backup=None): if backup is None or backup['status'] in stable_states: return backup - start = datetime.datetime.utcnow() + start = now() end = start + datetime.timedelta(seconds=wait_timeout) - while datetime.datetime.utcnow() < end: + while now() < end: module.debug('We are going to wait for the backup to finish its transition') response = account_api.get('/rdb/v1/regions/%s/backups/%s' % (module.params.get('region'), backup['id'])) diff --git a/plugins/modules/scaleway_lb.py b/plugins/modules/scaleway_lb.py index 3e43a8ae2b..5bd16c3f4e 100644 --- a/plugins/modules/scaleway_lb.py +++ b/plugins/modules/scaleway_lb.py @@ -161,6 +161,7 @@ RETURNS = ''' import datetime import time from ansible.module_utils.basic import AnsibleModule +from ansible_collections.community.general.plugins.module_utils.datetime import now from ansible_collections.community.general.plugins.module_utils.scaleway import SCALEWAY_REGIONS, SCALEWAY_ENDPOINT, scaleway_argument_spec, Scaleway STABLE_STATES = ( @@ -208,9 +209,9 @@ def wait_to_complete_state_transition(api, lb, force_wait=False): wait_timeout = api.module.params["wait_timeout"] wait_sleep_time = api.module.params["wait_sleep_time"] - start = datetime.datetime.utcnow() + start = now() end = start + datetime.timedelta(seconds=wait_timeout) - while datetime.datetime.utcnow() < end: + while now() < end: api.module.debug("We are going to wait for the load-balancer to finish its transition") state = fetch_state(api, lb) if state in STABLE_STATES: diff --git a/plugins/modules/statusio_maintenance.py b/plugins/modules/statusio_maintenance.py index e6b34b7098..0a96d0fb41 100644 --- a/plugins/modules/statusio_maintenance.py +++ b/plugins/modules/statusio_maintenance.py @@ -188,6 +188,10 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.common.text.converters import to_native from ansible.module_utils.urls import open_url +from ansible_collections.community.general.plugins.module_utils.datetime import ( + now, +) + def get_api_auth_headers(api_id, api_key, url, statuspage): @@ -270,11 +274,11 @@ def get_date_time(start_date, start_time, minutes): except (NameError, ValueError): return 1, None, "Couldn't work out a valid date" else: - now = datetime.datetime.utcnow() - delta = now + datetime.timedelta(minutes=minutes) + now_t = now() + delta = now_t + datetime.timedelta(minutes=minutes) # start_date - returned_date.append(now.strftime("%m/%d/%Y")) - returned_date.append(now.strftime("%H:%M")) + returned_date.append(now_t.strftime("%m/%d/%Y")) + returned_date.append(now_t.strftime("%H:%M")) # end_date returned_date.append(delta.strftime("%m/%d/%Y")) returned_date.append(delta.strftime("%H:%M")) diff --git a/tests/unit/plugins/callback/test_loganalytics.py b/tests/unit/plugins/callback/test_loganalytics.py index 17932ed5fa..4d7c2c9db9 100644 --- a/tests/unit/plugins/callback/test_loganalytics.py +++ b/tests/unit/plugins/callback/test_loganalytics.py @@ -9,8 +9,8 @@ from ansible.executor.task_result import TaskResult from ansible_collections.community.general.tests.unit.compat import unittest from ansible_collections.community.general.tests.unit.compat.mock import patch, Mock from ansible_collections.community.general.plugins.callback.loganalytics import AzureLogAnalyticsSource -from datetime import datetime +from datetime import datetime import json import sys @@ -32,10 +32,10 @@ class TestAzureLogAnalytics(unittest.TestCase): if sys.version_info < (3, 2): self.assertRegex = self.assertRegexpMatches - @patch('ansible_collections.community.general.plugins.callback.loganalytics.datetime') + @patch('ansible_collections.community.general.plugins.callback.loganalytics.now') @patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url') - def test_overall(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_overall(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a', @@ -52,10 +52,10 @@ class TestAzureLogAnalytics(unittest.TestCase): self.assertEqual(sent_data['event']['uuid'], 'myuuid') self.assertEqual(args[0], 'https://01234567-0123-0123-0123-01234567890a.ods.opinsights.azure.com/api/logs?api-version=2016-04-01') - @patch('ansible_collections.community.general.plugins.callback.loganalytics.datetime') + @patch('ansible_collections.community.general.plugins.callback.loganalytics.now') @patch('ansible_collections.community.general.plugins.callback.loganalytics.open_url') - def test_auth_headers(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_auth_headers(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.loganalytics.send_event(workspace_id='01234567-0123-0123-0123-01234567890a', diff --git a/tests/unit/plugins/callback/test_splunk.py b/tests/unit/plugins/callback/test_splunk.py index ddcdae24c7..c09540fc00 100644 --- a/tests/unit/plugins/callback/test_splunk.py +++ b/tests/unit/plugins/callback/test_splunk.py @@ -27,10 +27,10 @@ class TestSplunkClient(unittest.TestCase): self.mock_host = Mock('MockHost') self.mock_host.name = 'myhost' - @patch('ansible_collections.community.general.plugins.callback.splunk.datetime') + @patch('ansible_collections.community.general.plugins.callback.splunk.now') @patch('ansible_collections.community.general.plugins.callback.splunk.open_url') - def test_timestamp_with_milliseconds(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_timestamp_with_milliseconds(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.splunk.send_event( @@ -45,10 +45,10 @@ class TestSplunkClient(unittest.TestCase): self.assertEqual(sent_data['event']['host'], 'my-host') self.assertEqual(sent_data['event']['ip_address'], '1.2.3.4') - @patch('ansible_collections.community.general.plugins.callback.splunk.datetime') + @patch('ansible_collections.community.general.plugins.callback.splunk.now') @patch('ansible_collections.community.general.plugins.callback.splunk.open_url') - def test_timestamp_without_milliseconds(self, open_url_mock, mock_datetime): - mock_datetime.utcnow.return_value = datetime(2020, 12, 1) + def test_timestamp_without_milliseconds(self, open_url_mock, mock_now): + mock_now.return_value = datetime(2020, 12, 1) result = TaskResult(host=self.mock_host, task=self.mock_task, return_data={}, task_fields=self.task_fields) self.splunk.send_event(