From d1508e0991f965763a9a044b6174f4a74ace443a Mon Sep 17 00:00:00 2001 From: "Brad P. Crochet" Date: Fri, 3 Mar 2017 14:12:36 -0500 Subject: [PATCH] Add --utc flag to cron trigger create The server should not be doing any translation of times. It should be assumed that what is sent to the server is being sent as UTC. The addition of the --utc flags facilitates this. If the --utc flag is specified, then the --first-time passed is assumed to be already UTC and will not undergo a conversion. If it is not passed, the --first-time arg will be converted based on the the localtime of the client, then sent as UTC. Change-Id: I424d042d1cbdadae3aa14cd408d9f27d14823aef Depends-On: Ifbd63d9e1f56085928bede22ce4f2954e1b38991 Closes-Bug: #1654218 --- mistralclient/commands/v2/cron_triggers.py | 32 ++++++++++++- .../tests/unit/v2/test_cli_cron_triggers.py | 47 ++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/mistralclient/commands/v2/cron_triggers.py b/mistralclient/commands/v2/cron_triggers.py index a48c7d68..ebe699dc 100644 --- a/mistralclient/commands/v2/cron_triggers.py +++ b/mistralclient/commands/v2/cron_triggers.py @@ -13,6 +13,8 @@ # License for the specific language governing permissions and limitations # under the License. # +import datetime +import time from osc_lib.command import command @@ -123,7 +125,9 @@ class Create(command.ShowOne): parser.add_argument( '--first-time', type=str, - help="Date and time of the first execution", + default=None, + help=("Date and time of the first execution. Time is treated as " + "local time unless --utc is also specified"), metavar='' ) parser.add_argument( @@ -132,6 +136,11 @@ class Create(command.ShowOne): help="Number of wanted executions", metavar='' ) + parser.add_argument( + '--utc', + action='store_true', + help="All times specified should be treated as UTC" + ) return parser @@ -142,19 +151,38 @@ class Create(command.ShowOne): else: return {} + @staticmethod + def _convert_time_string_to_utc(time_string): + datetime_format = '%Y-%m-%d %H:%M' + + the_time = time_string + if the_time: + the_time = datetime.datetime.strptime( + the_time, datetime_format) + the_second = time.mktime(the_time.timetuple()) + the_utc_time = datetime.datetime.utcfromtimestamp(the_second) + the_time = the_utc_time.strftime(datetime_format) + + return the_time + def take_action(self, parsed_args): mistral_client = self.app.client_manager.workflow_engine wf_input = self._get_file_content_or_dict(parsed_args.workflow_input) wf_params = self._get_file_content_or_dict(parsed_args.params) + first_time = parsed_args.first_time + if not parsed_args.utc: + first_time = self._convert_time_string_to_utc( + parsed_args.first_time) + trigger = mistral_client.cron_triggers.create( parsed_args.name, parsed_args.workflow_identifier, wf_input, wf_params, parsed_args.pattern, - parsed_args.first_time, + first_time, parsed_args.count ) diff --git a/mistralclient/tests/unit/v2/test_cli_cron_triggers.py b/mistralclient/tests/unit/v2/test_cli_cron_triggers.py index f1635838..15116249 100644 --- a/mistralclient/tests/unit/v2/test_cli_cron_triggers.py +++ b/mistralclient/tests/unit/v2/test_cli_cron_triggers.py @@ -14,7 +14,9 @@ # under the License. # +import datetime import mock +import time from mistralclient.api.v2 import cron_triggers from mistralclient.commands.v2 import cron_triggers as cron_triggers_cmd @@ -37,11 +39,37 @@ TRIGGER = cron_triggers.CronTrigger(mock, TRIGGER_DICT) class TestCLITriggersV2(base.BaseCommandTest): + @mock.patch('mistralclient.commands.v2.cron_triggers.Create.' + '_convert_time_string_to_utc') @mock.patch('argparse.open', create=True) - def test_create(self, mock_open): + def test_create(self, mock_open, mock_convert): self.client.cron_triggers.create.return_value = TRIGGER mock_open.return_value = mock.MagicMock(spec=open) + result = self.call( + cron_triggers_cmd.Create, + app_args=['my_trigger', 'flow1', '--pattern', '* * * * *', + '--params', '{}', '--count', '5', '--first-time', + '4242-12-20 13:37', '--utc'] + ) + + mock_convert.assert_not_called() + self.assertEqual( + ( + 'my_trigger', 'flow1', {}, '* * * * *', + '4242-12-20 13:37', 5, '1', '1' + ), + result[1] + ) + + @mock.patch('mistralclient.commands.v2.cron_triggers.Create.' + '_convert_time_string_to_utc') + @mock.patch('argparse.open', create=True) + def test_create_no_utc(self, mock_open, mock_convert): + self.client.cron_triggers.create.return_value = TRIGGER + mock_open.return_value = mock.MagicMock(spec=open) + mock_convert.return_value = '4242-12-20 18:37' + result = self.call( cron_triggers_cmd.Create, app_args=['my_trigger', 'flow1', '--pattern', '* * * * *', @@ -49,6 +77,9 @@ class TestCLITriggersV2(base.BaseCommandTest): '4242-12-20 13:37'] ) + mock_convert.assert_called_once_with('4242-12-20 13:37') + self.client.cron_triggers.create.assert_called_once_with( + 'my_trigger', 'flow1', {}, {}, '* * * * *', '4242-12-20 18:37', 5) self.assertEqual( ( 'my_trigger', 'flow1', {}, '* * * * *', @@ -57,6 +88,20 @@ class TestCLITriggersV2(base.BaseCommandTest): result[1] ) + def test_convert_time_string_to_utc(self): + cmd = cron_triggers_cmd.Create(self.app, None) + + utc_value = cmd._convert_time_string_to_utc('4242-12-20 13:37') + + is_dst = time.daylight and time.localtime().tm_isdst > 0 + utc_offset = - (time.altzone if is_dst else time.timezone) + + expected_time = (datetime.datetime( + 4242, 12, 20, 13, 37) - datetime.timedelta( + 0, utc_offset)).strftime('%Y-%m-%d %H:%M') + + self.assertEqual(expected_time, utc_value) + def test_list(self): self.client.cron_triggers.list.return_value = [TRIGGER]