)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"071832b5d864191903cd7f00b2e172999543d2e1","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"f40c3430_418f9f7b","updated":"2025-07-21 18:13:22.000000000","message":"you have not updated\nhttps://github.com/openstack/watcher/blob/374750847f3ca2284b455792c414808a55e181ff/watcher/api/controllers/v1/types.py#L53","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"24c17092b9038cbf2e01b4ae0d7f7fe47940c897","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":3,"id":"a27dd721_503825bf","in_reply_to":"003f1366_a30ae668","updated":"2025-07-22 05:43:31.000000000","message":"I break this exception into two exceptions to give clear message to user for invalid internal and cron.","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"17f18fc3a4b1b748a50a36e3a2ba8b07e2ee2f3a","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":3,"id":"003f1366_a30ae668","in_reply_to":"f40c3430_418f9f7b","updated":"2025-07-22 05:42:18.000000000","message":"The validation method in IntervalOrCron is a boolean validaiton. If the current code fails it will raise the InvalidIntervalOrCron.\n\nDo we want to break InvalidIntervalOrCron exception into two exceptions one for invalid internal or another for invalid cron?","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"340bd03e8122f4145fd61a378c173ee248d2b69f","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"e2175ae9_9555917e","updated":"2025-07-23 10:25:17.000000000","message":"The positive case works fine but these are my findings:\n\n- There are certain differences between the accepted formats in coniter and appscheduler. The most important one is probably that apscheculer only accepts 5 fields format while croniter accepts 5, 6 and 7 fields (seconds and year are optional).\n\n- Also behavior is slightly different in other non usual cases. i.e. using sat#1,sun#2 in croniter means \"the first saturday and the second sunday of the month\" while appscheduler ignores #X and that means simply every saturday and sunday. Also keyword expersions as @weekly (https://pypi.org/project/croniter/#keyword-expressions) do not work in apscheduler.\n\nWe should at least document what cron format is accepted (basic 5-columns one if we move to apscheduler).\n\n- That means that some pre-existing interval values may fail after the migration (i.e. 6-fields intervals).\n  - When/if that happens the behavior of watcher is odd, not only wrong format continuous audits fail to execute but any other ongoing continuous audit created after the \"bad-formatted\" one, will also fail to schedule next runs as the worker responsible of scheduling fails with uncatched exception)\n  - The good part is that the interval of an ongoing continuous action can be updated using `openstack optimize audit update \u003caudit\u003e replace interval\u003d\u003cnew interval\u003e`.\n  - I\u0027m not entirely sure about what should be the expected behavior in that case (existing ongoing continuous action with invalid format in upgrade case). currently, the action simply stays in ongoing state but no new runs are scheduled. Is this faine or we should move it to FAILED or some other state (SUSPENDED?).\n  \nIIUC, croniter has been revived and moving out of croniter is not longer required but just trying to avoid a dependency, is this correct?. If that\u0027s the case, i\u0027d say croniter is more featurefull that apscheduler, tbh.\n\nSaid that, apscheduler may be good enough, if the consensus is to move out of croniter, I\u0027d say we should document the cron formats we are accepting and improving error handling when using _next_cron_time in continuous.py.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"1c866a761f4c079240aa6324686035280c079fe3","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"e637c286_988a485e","updated":"2025-07-22 09:00:19.000000000","message":"check-rdo","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7b636d83be8f1e79ea8d006ab09531cd79a00856","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"899f1ca1_ab61a36b","updated":"2025-07-29 20:33:26.000000000","message":"lets add this to the agenda for the next team meeting\ni think we need","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"7b636d83be8f1e79ea8d006ab09531cd79a00856","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"2d0db2af_d707c816","in_reply_to":"067f2db2_7bf13414","updated":"2025-07-29 20:33:26.000000000","message":"the next runtime is separate form the specification in the audit.\n\nthat is just the computed value so it does not impact if  5 or 7 column format is supported.\n\n\nthat is encoded in the interval filed which is a sting\n    op.alter_column(\u0027audits\u0027, \u0027interval\u0027, existing_type\u003dsa.String(36),\n                    nullable\u003dTrue)\n                    \ni think  the best path forward if we want to consider the 6/7 column format supported. i don\u0027t see any evidence that it was ever officially supported but it was also not blocked.\n\nfirst we need a watcher status check to detect if any audits are using an incomparable interval format.\n\nsecond we need to deprecate the use of 6/7 column format and log a warning when its used. we can do that by trying to use aspschduler then fallback to using cronitoer if apscheduler cannot parse it. but we could do it other ways.\n\nthird we need to do one of the following\n1.) do the migration automatically on load from the db.\n2.) provide a CLI tool to do an online migration of the data.\n3.) document a manual procedure to do the conversation via the api.\n\n\nforth in a future release 2026.2 we will drop the fallback and only use apscheduler.\n\nif we don\u0027t consider the 6/7 column format as being supported today we can just do step 3.3 or 3.2. i.e. document a way to convert existing unsupported formats into the supported form or provide a tool to do that.\n\ni agree with alfredo that we shoudl not allow there to be an error that prevent the applier form working.\nso what we will need to do is catch the excption form apscheudler, move the audit to error and log why. if we have status message filed form the skip feature we can also record the reason there.\n\nregardless fo the decision we need to start validating the interval format in the api on any audit and audit templeate creation and update.  if it fails format validation we shoudl return a 400 bad request with a descriptive error message.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"8606735af2108c680b6e69d9e037b58f7fbe6a4e","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"270bdf9d_b8243a76","in_reply_to":"069a2b81_7bd84dbe","updated":"2025-07-24 10:46:06.000000000","message":"Thank you @seanmooney8202@yahoo.ie @amoralej@redhat.com for the detailed review,\nI will try to update following things in cr:\n- I will keep the croniter deps and provide a migration code to validate the cron input and convert it from croniter to appschular format.\n   - Cases to handle:\n      - usage of @ keyword\n      - cases related to first sat or sun.\n- In the same patch, I will also add deprecation for croniter deps will remove in 2026.2\n- In a seperate patch, I will add a detailed doc around support formated of cron interval used in watcher for continous audit with test coverage.\n\nDo let me know if I missed anything from above discussion.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"4a53d64ca6562c2c481e7eaf779c64db7d13e3ae","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"806a969a_58e92a0c","in_reply_to":"07c97fc9_f4518e94","updated":"2025-07-25 02:16:39.000000000","message":"I grepped over releasenotes. I found only one release note mentioning about cron https://github.com/openstack/watcher/blob/master/releasenotes/notes/cron-based-continuous-audits-c3eedf28d9752b37.yaml\n```\n  - There is new ability to create Watcher continuous audits with cron\n    interval. It means you may use, for example, optional argument\n    \u0027--interval \"\\*/5 \\* \\* \\* \\*\"\u0027 to launch audit every 5 minutes.\n    These jobs are executed on a best effort basis and therefore, we\n    recommend you to use a minimal cron interval of at least one minute.\n\n```\nFrom above, it talks about 5 coulumn crontab format from the example.\n\nI also checked sqlachemy db table format from https://github.com/openstack/watcher/blob/master/watcher/db/sqlalchemy/alembic/versions/d098df6021e2_cron_support_for_audit.py\n```\n op.add_column(\u0027audits\u0027,\n                  sa.Column(\u0027next_run_time\u0027, sa.DateTime(), nullable\u003dTrue))\n\n```\nIt stores in DateTime format which means it includes year, month, day, hour, min, second format. Where as cron support Minute, Hour, Day-of-Month, Month, and Day-of-Week format.\n\nI assume due to croniter usage, it was support 6,7 column cron format. But in standard cron pratice, 5 coulumn is preferred.\n\n@seanmooney8202@yahoo.ie @amoralej@redhat.com, Since there is no mention of cron format, is it safe to go with 5 cloumn cron format?","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"646f44865fea3a7bdfc7c62d6e04591d214390fe","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"e2a033c9_70835d2b","in_reply_to":"270bdf9d_b8243a76","updated":"2025-07-24 11:52:43.000000000","message":"well dont do that yet we are not finished dicussing this.\n\nif we have no tests that use the 6/7 columb version and there is no docuementation of its usage or dicussion in the orgianl spec for continuous audits we are more then justified in stating ti was never supproted.\n\nthat means we can provide a migration tool kit as an optional extra and move the depenicy on cronitor to just taht tool. \n\ni.e. we will move croniter into extras in setup.cfg and remove it form requirements.txt\n\nand only that migration tool will use it.\n\nthat tools need to do two things 1 check if any intervals need to be updated (i.e. a dry run mode/status mode) and 2 do the convertion.\n\nwatcher-status is the approate thing to extend to check if we need to do the convertion\n\nand \n\ndb manage can have a online migration command to do the convertion.\n\nor  we could do nothing beyond docs and release note.\n\nwe have a number of options that we need to evacualte.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"191158289ed45d4824525724dc38d247c0e8d4bc","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"067f2db2_7bf13414","in_reply_to":"806a969a_58e92a0c","updated":"2025-07-28 11:29:03.000000000","message":"Supporting 5-columns only cron format can be good and should be documented, including release notes. However, IMO from upgrade PoV,we must covered as discussed in previous comments, including:\n1.- cron syntax errors in existing intervals validation should not cause an unmanaged worker error which causes other continuous audits to also not being evaluated.\n2.- A migration tool to migrate pre-existing active audits would be good, but imo that does not avoid us of doing [1].\n3. If we set a deprecation release where we would still be using croniter, it would be nice to validate new ongoing audits with apscheduler so that we\u0027d be sure that new audits would be compatiblle with it.\nAbout microversion, given the type of data and the lack of clear behavior I\u0027d say it\u0027s not needed and a releasenote whould be enough, but i\u0027m not sure about it.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"0392af0ed0f730c0d8c7e575bc87a586440df843","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"b7c4a111_4b926700","in_reply_to":"899f1ca1_ab61a36b","updated":"2025-07-29 20:34:08.000000000","message":"i think we need to also discuss this on the mailing list to decied on a path forward.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"6ad09b1d4aacf4cc18fbfd26453f58a2df060690","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"069a2b81_7bd84dbe","in_reply_to":"e2175ae9_9555917e","updated":"2025-07-23 13:03:28.000000000","message":"so this is a case where the api was not well specficed before and as a resutl the accpated values are partly implemation defined.\n\nthat is generally not considered acceptable for a service but its legacy tech debt so i agree we should document what is and is not accpated.\n\nin terms fo existing value i think we shoudl consider providing a online data migration tool that will convert the existing values form croniter format to apscheler format.\n\n\nthere are a few ways to do this.\nwe could keep the croniter dep this cycle and next just for the upgade of the data and do the conversion on load.\n\nwe could also add a watcher-manage command to do this as an online data migration\nin either case i think we are going to have to keep coniter until 2026.2 unless we were to backport the cli tool to 2025.1\n\ni dont think swaping to apscheduler is backportable and if we are tightening our api requirements that technally could be argued as needing a api microversion.\n\nso we likely shoudl get gmann  to weigh in here.\n\ntop be clear i wond not consider every feature cornitor supproted to be part of the api contract of watcher.\nthat is not how api work in openstack.\nbut we do need to think about the upgreade impact.\n\nsince there isnt partity we may need to deprecate and provide a multi cycle upgrade path by supproting doing the data migration in 2026.1 meaning the removal can only happen in 2026.2","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"9680329f09378061efb06dfaca24bfc9c5dbdd51","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":5,"id":"07c97fc9_f4518e94","in_reply_to":"e2a033c9_70835d2b","updated":"2025-07-24 12:50:09.000000000","message":"@seanmooney8202@yahoo.ie, Based on my initial scan over watcher-specs.\nBelow are the 3 specs linked with continous audit\nhttps://github.com/openstack/watcher-specs/blob/master/specs/newton/implemented/continuously-optimization.rst\nhttps://github.com/openstack/watcher-specs/blob/master/specs/pike/implemented/cron-based-continuous-audits.rst\nhttps://github.com/openstack/watcher-specs/blob/master/specs/stein/implemented/add-start-end-time-for-continuous-audit.rst\n\nhttps://github.com/openstack/watcher-specs/blob/master/specs/pike/implemented/cron-based-continuous-audits.rst mentions about passing crontab syntax with continous audit\nusing croniter module. It does not mention any thing crontab format limit.\nExample from above spec:\n```\nFor example, Watcher had to run audit at 7:30 am, but services went down and we have restored it only at 9:00 am. Using interval with 3600 value, Watcher has to set next run time at 9:30 am.\n```\nBased on that, I think should avoid worrying about supporting croniter 6,7 coulumn?","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"}],"watcher/common/exception.py":[{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"a3ec4ce500075a5cb149ad2d18acd489baa003a3","unresolved":true,"context_lines":[{"line_number":204,"context_line":""},{"line_number":205,"context_line":""},{"line_number":206,"context_line":"class InvalidCron(Invalid):"},{"line_number":207,"context_line":"    msg_fmt \u003d _(\"cron syntax but received %(name)s\")"},{"line_number":208,"context_line":""},{"line_number":209,"context_line":""},{"line_number":210,"context_line":"class InvalidInterval(Invalid):"}],"source_content_type":"text/x-python","patch_set":5,"id":"a10aedf4_38532d13","line":207,"range":{"start_line":207,"start_character":0,"end_line":207,"end_character":52},"updated":"2025-07-30 11:39:52.000000000","message":"You need to improve this message here IMO","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"}],"watcher/common/utils.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"071832b5d864191903cd7f00b2e172999543d2e1","unresolved":true,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Return True is submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        CronTrigger.from_crontab(value)"},{"line_number":74,"context_line":"    except Exception as e:"},{"line_number":75,"context_line":"        raise exception.CronFormatIsInvalid(message\u003dstr(e))"},{"line_number":76,"context_line":"    return True"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"def safe_rstrip(value, chars\u003dNone):"}],"source_content_type":"text/x-python","patch_set":3,"id":"07b81846_e639f5ad","line":76,"range":{"start_line":70,"start_character":0,"end_line":76,"end_character":15},"updated":"2025-07-21 18:13:22.000000000","message":"we should change the signiture of this method to return the cronTrigger if its valid.\n```suggestion\ndef is_cron_like(value):\n    \"\"\"Returns a CronTriger if the submitted value is like cron syntax\"\"\"\n    try:\n        return CronTrigger.from_crontab(value)\n    except Exception as e:\n        raise exception.CronFormatIsInvalid(message\u003dstr(e))\n```","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"307f871f3b8d151fbfdcdb76e1dfefc19b18d1b4","unresolved":true,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Return True is submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        CronTrigger.from_crontab(value)"},{"line_number":74,"context_line":"    except Exception as e:"},{"line_number":75,"context_line":"        raise exception.CronFormatIsInvalid(message\u003dstr(e))"},{"line_number":76,"context_line":"    return True"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"def safe_rstrip(value, chars\u003dNone):"}],"source_content_type":"text/x-python","patch_set":3,"id":"0a255d5c_7a8f5cd1","line":76,"range":{"start_line":70,"start_character":0,"end_line":76,"end_character":15},"in_reply_to":"07b81846_e639f5ad","updated":"2025-07-22 04:26:37.000000000","message":"Done","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"6ad09b1d4aacf4cc18fbfd26453f58a2df060690","unresolved":false,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Return True is submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        CronTrigger.from_crontab(value)"},{"line_number":74,"context_line":"    except Exception as e:"},{"line_number":75,"context_line":"        raise exception.CronFormatIsInvalid(message\u003dstr(e))"},{"line_number":76,"context_line":"    return True"},{"line_number":77,"context_line":""},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"def safe_rstrip(value, chars\u003dNone):"}],"source_content_type":"text/x-python","patch_set":3,"id":"b535c355_b2625c41","line":76,"range":{"start_line":70,"start_character":0,"end_line":76,"end_character":15},"in_reply_to":"0a255d5c_7a8f5cd1","updated":"2025-07-23 13:03:28.000000000","message":"Done","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":30002,"name":"Douglas Viroel","email":"viroel@gmail.com","username":"dviroel"},"change_message_id":"a3ec4ce500075a5cb149ad2d18acd489baa003a3","unresolved":true,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Returns a CronTriger if the submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        return CronTrigger.from_crontab(value)"}],"source_content_type":"text/x-python","patch_set":5,"id":"51da9150_9f01f482","line":70,"range":{"start_line":70,"start_character":4,"end_line":70,"end_character":16},"updated":"2025-07-30 11:39:52.000000000","message":"this was already bad before, for me a function `is_something` should only return true or false. We should rename to to_contrigger/from_contab, or something similar, which is what the function is doing now.","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f9b3e34860f074b58bdab01d383b27eea94d43a3","unresolved":true,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Returns a CronTriger if the submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        return CronTrigger.from_crontab(value)"}],"source_content_type":"text/x-python","patch_set":5,"id":"d7fc7232_5e4c5ff0","line":70,"range":{"start_line":70,"start_character":4,"end_line":70,"end_character":16},"in_reply_to":"51da9150_9f01f482","updated":"2025-07-30 15:12:03.000000000","message":"ya im not a huge fan of the name. what i wanted to aovid was having to parse the object form string to a value twice.\n\nto_contrigger/from_contab are both better names","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"111884b9920d68660337921e591f1c8185872ef5","unresolved":true,"context_lines":[{"line_number":67,"context_line":"is_int_like \u003d strutils.is_int_like"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def is_cron_like(value):"},{"line_number":71,"context_line":"    \"\"\"Returns a CronTriger if the submitted value is like cron syntax\"\"\""},{"line_number":72,"context_line":"    try:"},{"line_number":73,"context_line":"        return CronTrigger.from_crontab(value)"}],"source_content_type":"text/x-python","patch_set":5,"id":"926ae66b_76f43de4","line":70,"range":{"start_line":70,"start_character":4,"end_line":70,"end_character":16},"in_reply_to":"d7fc7232_5e4c5ff0","updated":"2025-08-12 09:54:57.000000000","message":"Sure, I will update the changes.\nI also took the time to add docs around continous audit https://review.opendev.org/c/openstack/watcher/+/957098","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"}],"watcher/decision_engine/audit/continuous.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"071832b5d864191903cd7f00b2e172999543d2e1","unresolved":true,"context_lines":[{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    @staticmethod"},{"line_number":99,"context_line":"    def _next_cron_time(audit):"},{"line_number":100,"context_line":"        if utils.is_cron_like(audit.interval):"},{"line_number":101,"context_line":"            trigger \u003d CronTrigger.from_crontab(audit.interval)"},{"line_number":102,"context_line":"            return trigger.get_next_fire_time("},{"line_number":103,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"    @classmethod"},{"line_number":106,"context_line":"    def execute_audit(cls, audit, request_context):"}],"source_content_type":"text/x-python","patch_set":3,"id":"ccfaf173_b1843986","line":103,"range":{"start_line":100,"start_character":8,"end_line":103,"end_character":68},"updated":"2025-07-21 18:13:22.000000000","message":"```suggestion\n        if (trigger :\u003d utils.is_cron_like(audit.interval)):\n            return trigger.get_next_fire_time(\n                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))\n```","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"6ad09b1d4aacf4cc18fbfd26453f58a2df060690","unresolved":false,"context_lines":[{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    @staticmethod"},{"line_number":99,"context_line":"    def _next_cron_time(audit):"},{"line_number":100,"context_line":"        if utils.is_cron_like(audit.interval):"},{"line_number":101,"context_line":"            trigger \u003d CronTrigger.from_crontab(audit.interval)"},{"line_number":102,"context_line":"            return trigger.get_next_fire_time("},{"line_number":103,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"    @classmethod"},{"line_number":106,"context_line":"    def execute_audit(cls, audit, request_context):"}],"source_content_type":"text/x-python","patch_set":3,"id":"1c9f0c3b_e356b048","line":103,"range":{"start_line":100,"start_character":8,"end_line":103,"end_character":68},"in_reply_to":"109615a8_ee51945e","updated":"2025-07-23 13:03:28.000000000","message":"Done","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"307f871f3b8d151fbfdcdb76e1dfefc19b18d1b4","unresolved":true,"context_lines":[{"line_number":97,"context_line":""},{"line_number":98,"context_line":"    @staticmethod"},{"line_number":99,"context_line":"    def _next_cron_time(audit):"},{"line_number":100,"context_line":"        if utils.is_cron_like(audit.interval):"},{"line_number":101,"context_line":"            trigger \u003d CronTrigger.from_crontab(audit.interval)"},{"line_number":102,"context_line":"            return trigger.get_next_fire_time("},{"line_number":103,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"    @classmethod"},{"line_number":106,"context_line":"    def execute_audit(cls, audit, request_context):"}],"source_content_type":"text/x-python","patch_set":3,"id":"109615a8_ee51945e","line":103,"range":{"start_line":100,"start_character":8,"end_line":103,"end_character":68},"in_reply_to":"ccfaf173_b1843986","updated":"2025-07-22 04:26:37.000000000","message":"Done","commit_id":"8969c2336b85d912e3bdb8fbaf419a3f9661e782"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"6ad09b1d4aacf4cc18fbfd26453f58a2df060690","unresolved":true,"context_lines":[{"line_number":95,"context_line":"        return solution"},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    @staticmethod"},{"line_number":98,"context_line":"    def _next_cron_time(audit):"},{"line_number":99,"context_line":"        if (trigger :\u003d utils.is_cron_like(audit.interval)):"},{"line_number":100,"context_line":"            return trigger.get_next_fire_time("},{"line_number":101,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"    @classmethod"},{"line_number":104,"context_line":"    def execute_audit(cls, audit, request_context):"}],"source_content_type":"text/x-python","patch_set":5,"id":"6a3a301e_0de7390b","line":101,"range":{"start_line":98,"start_character":0,"end_line":101,"end_character":68},"updated":"2025-07-23 13:03:28.000000000","message":"as an aside we probly should revisit how this is used.\n\nwe really should not need to have an if and should know at this point that its cron like.\n\nthis will raise if its not cron like so maybe we shoudl do this instead.\n\n```suggestion\n    def _next_cron_time(audit):\n        trigger \u003d utils.is_cron_like(audit.interval_\n        return trigger.get_next_fire_time(\n            None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))\n```\nbut also if we want to include the timezone info we shoudl do this\n\n```\n    def _next_cron_time(audit):\n        trigger \u003d utils.is_cron_like(audit.interval_\n        return trigger.get_next_fire_time(\n            None, timeutils.utcnow(with_timezone\u003dtrue))\n```\n\nthat will allow use to remove the import.\n\nits not quite enough to remove our useage of dateutil entirely but it gets use closer to being able to drop that as a depency in a follow up","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"fe20c51f7d0c4e4d3429dcc5a490b0669762c089","unresolved":true,"context_lines":[{"line_number":95,"context_line":"        return solution"},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    @staticmethod"},{"line_number":98,"context_line":"    def _next_cron_time(audit):"},{"line_number":99,"context_line":"        if (trigger :\u003d utils.is_cron_like(audit.interval)):"},{"line_number":100,"context_line":"            return trigger.get_next_fire_time("},{"line_number":101,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"    @classmethod"},{"line_number":104,"context_line":"    def execute_audit(cls, audit, request_context):"}],"source_content_type":"text/x-python","patch_set":5,"id":"b2e29f6f_3a50d20f","line":101,"range":{"start_line":98,"start_character":0,"end_line":101,"end_character":68},"in_reply_to":"6a3a301e_0de7390b","updated":"2025-07-24 12:03:38.000000000","message":"Added python-dateutil removal bug https://bugs.launchpad.net/watcher/+bug/2118404","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"},{"author":{"_account_id":16312,"name":"Alfredo Moralejo","email":"amoralej@redhat.com","username":"amoralej"},"change_message_id":"340bd03e8122f4145fd61a378c173ee248d2b69f","unresolved":true,"context_lines":[{"line_number":96,"context_line":""},{"line_number":97,"context_line":"    @staticmethod"},{"line_number":98,"context_line":"    def _next_cron_time(audit):"},{"line_number":99,"context_line":"        if (trigger :\u003d utils.is_cron_like(audit.interval)):"},{"line_number":100,"context_line":"            return trigger.get_next_fire_time("},{"line_number":101,"context_line":"                None, timeutils.utcnow().replace(tzinfo\u003dtz.tzutc()))"},{"line_number":102,"context_line":""},{"line_number":103,"context_line":"    @classmethod"},{"line_number":104,"context_line":"    def execute_audit(cls, audit, request_context):"},{"line_number":105,"context_line":"        self \u003d cls()"}],"source_content_type":"text/x-python","patch_set":5,"id":"602f6dac_926dfba1","line":102,"range":{"start_line":99,"start_character":0,"end_line":102,"end_character":1},"updated":"2025-07-23 10:25:17.000000000","message":"See may overall comment about upgrade case. We should handle exceptions when using this method assuming that this may return watcher.common.exception.CronFormatIsInvalid exception, like in:\n\n```\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default   File \"/usr/lib/python3.9/site-packages/watcher/decision_engine/audit/continuous.py\", line 99, in _next_cron_time\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default     if (trigger :\u003d utils.is_cron_like(audit.interval)):\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default   File \"/usr/lib/python3.9/site-packages/watcher/common/utils.py\", line 75, in is_cron_like\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default     raise exception.CronFormatIsInvalid(message\u003dstr(e))\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default watcher.common.exception.CronFormatIsInvalid: Wrong number of fields; got 6, expected 5\n2025-07-23 09:44:58.649 33 ERROR apscheduler.executors.default \n```","commit_id":"0727b2d8b40731d7f5d0a42c133d57127bc5b6c9"}]}
