Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Persian calendar results in notification loop at every next Munki run #1065

Open
aysiu opened this issue Dec 13, 2020 · 3 comments
Open

Comments

@aysiu
Copy link
Contributor

aysiu commented Dec 13, 2020

Issue

If you set the calendar that root uses to be the Persian (instead of Gregorian) calendar, Munki runs result in a user notification loop.

Steps to replicate

  1. Run sudo defaults write /Library/Preferences/.GlobalPreferences.plist AppleLocale "en_US@calendar=persian" or sudo defaults write /Library/Preferences/.GlobalPreferences.plist AppleLocale "en_AF"
  2. Have a pending install that can't be installed unattended (either require a restart or having a blocking application open)
  3. Run sudo managedsoftwareupdate --auto
  4. At the end of each Munki run, something like this will appear in the logs:
Dec 12 2020 20:49:40 -0800 ### Beginning unattended installer session ###
Dec 12 2020 20:49:40 -0800 Processing installs
Dec 12 2020 20:49:40 -0800     Skipping install of Skype because it's not unattended.
Dec 12 2020 20:49:40 -0800 ###    End unattended installer session    ###
Dec 12 2020 20:49:40 -0800     Allowing idle sleep
Dec 12 2020 20:49:40 -0800 Finishing...
Dec 12 2020 20:49:40 -0800 Saving application inventory...
Dec 12 2020 20:49:46 -0800     Performing postflight tasks...
Dec 12 2020 20:49:46 -0800 ### Ending managedsoftwareupdate run ###
Dec 12 2020 20:49:46 -0800 Notifying user of available updates.
Dec 12 2020 20:49:46 -0800 LastNotifiedDate was 1399-09-23 04:40:43 +0000

and the user will see a notification of a pending update
Screen Shot 1399-09-22 at 8 49 52 PM
even though
defaults read /Library/Preferences/ManagedInstalls.plist LastNotifiedDate beforehand would show 1399-09-23 04:40:43 +0000, which is within the last day, and Munki will successfully write a new LastNotifiedDate of 1399-09-23 04:49:46 +0000 after the run.

Settings notes

This is with DaysBetweenNotifications = 1 and UseNotificationCenterDays = 1, which I believe are the default values, and

Munki version

managedsoftwareupdate --version
5.2.0.4237

User calendar seems to have no relevance

I thought maybe this might be because of a mismatch between user prefs (since Managed Software Center operates in the user space) and root prefs (since Munki runs as root), but if I set both user (defaults write ~/Library/Preferences/.GlobalPreferences.plist AppleLocale "en_US@calendar=persian") and root to use the Persian calendar, I still get a notification loop.

Potential source of issue

I added in some debug output on a test machine to see what was happening:

    lastNotifiedString = prefs.pref('LastNotifiedDate')
    munkilog.log("Last notified string is {}".format(lastNotifiedString))
    try:
        daysBetweenNotifications = int(
            prefs.pref('DaysBetweenNotifications'))
    except ValueError:
        display.display_warning(
            'DaysBetweenNotifications is not an integer: %s'
            % prefs.pref('DaysBetweenNotifications'))
        # continue with the default DaysBetweenNotifications
        daysBetweenNotifications = 1
    now = NSDate.new()
    munkilog.log("Now is {}".format(now))
    nextNotifyDate = now
    if lastNotifiedString:
        lastNotifiedDate = NSDate.dateWithString_(lastNotifiedString)
        munkilog.log("Last notified date was {}".format(lastNotifiedDate))
        interval = daysBetweenNotifications * (24 * 60 * 60)
        if daysBetweenNotifications > 0:
            # we make this adjustment so a 'daily' notification
            # doesn't require 24 hours to elapse
            # subtract 6 hours
            interval = interval - (6 * 60 * 60)
        munkilog.log("Interval is {}".format(interval))
        nextNotifyDate = lastNotifiedDate.dateByAddingTimeInterval_(interval)
        munkilog.log("Next notify date is {}".format(nextNotifyDate))
        munkilog.log("Interval since last date is {}".format(now.timeIntervalSinceDate_(nextNotifyDate)))
    if force or now.timeIntervalSinceDate_(nextNotifyDate) >= 0:
        # record current notification date
        munkilog.log("Setting LastNotifiedDate to {}".format(now))
        prefs.set_pref('LastNotifiedDate', now)

        munkilog.log('Notifying user of available updates.')
        munkilog.log('LastNotifiedDate was %s' % lastNotifiedString)

and, for the Persian calendar, that resulted in

Dec 13 2020 20:13:07 -0800 ### Ending managedsoftwareupdate run ###
Dec 13 2020 20:13:07 -0800 Last notified string is 1399-09-24 04:12:40 +0000
Dec 13 2020 20:13:07 -0800 Now is 1399-09-24 04:13:07 +0000
Dec 13 2020 20:13:07 -0800 Last notified date was 0778-07-10 04:12:40 +0000
Dec 13 2020 20:13:07 -0800 Interval is 64800
Dec 13 2020 20:13:07 -0800 Next notify date is 0778-07-10 22:12:40 +0000
Dec 13 2020 20:13:07 -0800 Interval since last date is 19603144827.187416
Dec 13 2020 20:13:07 -0800 Setting LastNotifiedDate to 1399-09-24 04:13:07 +0000
Dec 13 2020 20:13:07 -0800 Notifying user of available updates.
Dec 13 2020 20:13:07 -0800 LastNotifiedDate was 1399-09-24 04:12:40 +0000

And with the Gregorian (instead of Persian) calendar, that same debug output looks like this:

Dec 13 2020 20:14:12 -0800 ### Ending managedsoftwareupdate run ###
Dec 13 2020 20:14:12 -0800 Last notified string is 2020-12-14 04:13:07 +0000
Dec 13 2020 20:14:12 -0800 Now is 2020-12-14 04:14:12 +0000
Dec 13 2020 20:14:12 -0800 Last notified date was 2020-12-14 04:13:07 +0000
Dec 13 2020 20:14:12 -0800 Interval is 64800
Dec 13 2020 20:14:12 -0800 Next notify date is 2020-12-14 22:13:07 +0000
Dec 13 2020 20:14:12 -0800 Interval since last date is -64734.21926903725

I think the main issue is that NSDate.dateWithString_(lastNotifiedString) doesn't take into account what type of calendar is being used, so it translates a Gregorian date string into an appropriate date object but translates a Persian date string into a completely different date object.

@gregneagle
Copy link
Contributor

I can't imagine I'll find the time to give this the attention it might deserve. Happy for someone else to take a stab and create a PR.

@aysiu
Copy link
Contributor Author

aysiu commented Feb 22, 2021

No worries. Thanks for having a look. If I can figure out a proper fix, I'll make a PR. I can think of some not-proper workarounds that make safe-ish but not really 100% safe assumptions about Persian calendar date strings.

@aysiu
Copy link
Contributor Author

aysiu commented Feb 23, 2021

This may be a bit of too drastic a change to address this one issue, but would you consider a PR for storing last notification in epoch/unix timestamp instead of as a string based on locale-based date-time?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants