super icon indicating copy to clipboard operation
super copied to clipboard

Superman 5.0.0 running update before user gets opportunity to log in

Open david-london opened this issue 1 year ago • 13 comments

Hi

First - I really, really like this project - thank you.

I had two test users report that with Superman 5.0.0 their machines restarted shortly after they started up in the morning and installed the just released update with no chance of deferral. Both users reported that they logged on as soon as the machines came up but when I look in the super.log file I see this kind of entry

Tue Oct 29 08:22:42 dep69226 super[435]: Status: No GUI user currently logged in.

I got them to run "last" to try and figure out timing

itadmin    ttys000  10.131.249.177         Tue 29 Oct 09:42 - 14:19  (04:36)
itadmin    ttys000  10.131.249.177         Tue 29 Oct 09:10 - 09:19  (00:08)
00014170   console                         Tue 29 Oct 08:37   still logged in
00014170   console                         Tue 29 Oct 08:36 - 08:37  (00:00)
reboot time                                Tue 29 Oct 08:35
shutdown time                              Tue 29 Oct 08:32
root       console                         Tue 29 Oct 08:30 - shutdown  (00:01)
00014170   console                         Tue 29 Oct 08:23 - 08:30  (00:07)
reboot time                                Tue 29 Oct 08:22

So if I'm reading this correctly, the machine started at 8:22, super started doing stuff at 8:22:42 and then the user logged in at 8:23. Super is just too darn quick!

Is there a way to disable super from doing anything when nobody is logged in? With people being mobile so much they frequently shut down. There was apparently no pop up to allow deferral but I can see that was because this started when super decided nobody was logged in.

I'm just trying to avoid somebody getting an update like this and they are just launching into a presentation. The big feature for me is the ability to defer for a set number of days but it seems like there is a small window where super can just bypass everything. I appreciate that in some cases you want super to install when nobody is logged in - I have labs where that's my plan but in the scenario above even if it waited for a set time to make sure someone wasn't just booting, it would be helpful

2024-10-29_dep69226_super.log dep69226_last.txt

david-london avatar Oct 30 '24 08:10 david-london

Indeed... super started up and saw that no one was logged in... and then procededed to install.

This would need to be a new feature to NOT do that since a lot of folks (in shared lab situtations) expcect super to automatically install if there is no current user.

Macjutsu avatar Nov 04 '24 20:11 Macjutsu

Thanks Kevin,

Yes, I want to take advantage of this "No GUI user currently logged in" for our labs. But for other people, it seems like super is too fast.

This is your baby but here's some suggestions:

  • Instead of a LaunchDaemon, have Super run as a LaunchAgent if some configuration setting is made to only run super when a user is logged on.
  • Have some sort of delay after restart variable that can be set to give the user at least a chance of logging in

I know you have a way bigger idea of how things work so as I said, just suggestions.

david-london avatar Nov 05 '24 02:11 david-london

No plans to move to an agent b/c that could cause a cascade of issues. That being said, I do plan to implement features that allows for control of super's workflow in reguards to user vs no user.

Macjutsu avatar Nov 05 '24 17:11 Macjutsu

We have seen this in our environment too. I understand that super sees that the user is not logged in and that starting the update flow is the correct logic but... I also think that the flow restarting a device with no warning to a user should not happen.

The improvements to the user experience and notification from super are one of the key things about it to me!

rjashton avatar Nov 20 '24 15:11 rjashton

We experienced the same in our environment.

As a workaround i have now modified the super-starter script to add a customizable delay after boot and just exit 0 when we are not past this delay. I guess 900 seconds (the value i chose) should be sufficient for everyone to sign in.

Of course i actually modified the super script (which writes the super-starter script).

This is a quick solution and may be implemented more elegant (e.g. call it by parameter).

Here is a diff output (includes some timeouts i modified too):

14a15,18 > # Delay super after system boot (in seconds) to prevent accidental update installation (with no warning at all) > BOOT_DELAY=900 > readonly BOOT_DELAY > 471c475 < TIMEOUT_INSTALLER_DOWNLOAD_SECONDS=300 --- > TIMEOUT_INSTALLER_DOWNLOAD_SECONDS=600 475c479 < TIMEOUT_INSTALLER_WORKFLOW_SECONDS=600 --- > TIMEOUT_INSTALLER_WORKFLOW_SECONDS=1800 479c483 < TIMEOUT_MDM_COMMAND_SECONDS=300 --- > TIMEOUT_MDM_COMMAND_SECONDS=900 483c487 < TIMEOUT_MDM_WORKFLOW_SECONDS=600 --- > TIMEOUT_MDM_WORKFLOW_SECONDS=900 3563a3568,3574 > > # Exit this script if last boot time was under \${BOOT_DELAY} seconds > kernel_boot_epoch=\$(sysctl -n kern.boottime | awk -F 'sec = |, usec' '{print \$2}') > current_time=\$(date +%s) > if [[ \$((current_time - kernel_boot_epoch)) -lt ${BOOT_DELAY} ]]; then > exit 0 > fi 10834c10845 < exit_clean --- > exit_clean

sch4llfl3g3l avatar Dec 13 '24 15:12 sch4llfl3g3l

Hey @sch4llfl3g3l that looks like a better idea than what I was thinking of. Looks like you put the block:

# Exit this script if last boot time was under \${BOOT_DELAY} seconds
kernel_boot_epoch=\$(sysctl -n kern.boottime | awk -F 'sec = |, usec' '{print \$2}')
current_time=\$(date +%s)
if [[ \$((current_time - kernel_boot_epoch)) -lt ${BOOT_DELAY} ]]; then
	exit 0
fi

about line 3565 at the start of the super-starter script inside the super script - yes?

Also the block:

# Delay super after system boot (in seconds) to prevent accidental update installation (with no warning at all)
BOOT_DELAY=900
readonly BOOT_DELAY

is around line 14 in super

I'll give this a go and see if I get any issues

david-london avatar Dec 18 '24 05:12 david-london

Hi @david-london

line 3565 is correct (that makes it the first condition to be checked). And BOOT_DELAY about line 14/15. If this would be integrated into a release it wasn't the right place, but so far it is convenient for me (separate from the original code and i can quickly change it there).

Take care of the escaping backslashes when copying the code.

You can add a line with an echo message to a file in /tmp above the "exit 0", for debugging purposes. That way you can check if the condition is properly executed after boot. If so it must write 15 lines into that file if the BOOT_DELAY is 900 seconds (15 minutes - the launch daemon runs every minute)

sch4llfl3g3l avatar Dec 18 '24 11:12 sch4llfl3g3l

Hi @sch4llfl3g3l

It looks to be working for me. The 15 minutes delay from startup seems like a reasonable time too.

I actually think this is a good compromise with how Kevin designed it. However, knowing the tight windows people have with labs sometimes, I think a way of turning this on via a config profile or startup settings would be needed for wider use.

david-london avatar Dec 19 '24 01:12 david-london

Hi @sch4llfl3g3l I thought a bit more about this and decided that I don't ever want super to run before someone logs in (at least for regular machines). I've borrowed your idea of doing a check in super-starter and instead of a delay, just get it to check if someone is logged in and bail out if there isn't anyone logged in.

I have this around line 15

# Disable if not logged on
# see line 3572
DISABLE_IF_NOT_LOGGED_ON="true"

and this in the super-starter code area (around line 3572) as the first bit of code

#**# Exit this script if no user is logged on to the computer - i.e. disable super before logon

DISABLE_BEFORE_LOGON="$DISABLE_IF_NOT_LOGGED_ON"
if [[ "\$DISABLE_BEFORE_LOGON" = true ]]; then
	consoleUser=\$(stat -f %Su /dev/console)
	echo "\$consoleUser"    
	if [ "\$consoleUser" == "root" ]; then
		# nobody logged on
		echo "Nobody logged on so exiting"
		exit 0
	fi
fi

david-london avatar Mar 04 '25 08:03 david-london

Hi @david-london

Managed to spend some more time into this now.

I have parametrized the two options (boot delay, no unattended install of updates) using Kevin's logic. I guess that's the way to go (the most proper one and the logic is already there - it just has to be reused / adapted)

Like: --workflow-disable-no-user-install (command line parameter) OR WorkflowDisableNoUserInstall (Payload / plist) --deferral-timer-workflow-lastboot=minutes (command line parameter) OR DeferralTimerWorkflowLastBoot (Payload / plist)

I set a default value of 5 minutes for the boot delay (and a minimum of 2 minutes / maximum of 1 hour).

I still have to test it, maybe tomorrow or at the end of this week. The boot delay is already working by Payload key / value.

So we get rid of the workarounds (mine was only a workaround and yours is running a user session check that is already better implemented in the existing code).

i can make a diff and - of course - hand this over to @Macjutsu (i have currently no idea how to make a proposal or change request on Github) when i'm done with checking functionality and possible side effects.

sch4llfl3g3l avatar Mar 11 '25 14:03 sch4llfl3g3l

So here is a patch file that will add 2 parameters to super: --workflow-disable-no-user-install (by command line) OR WorkflowDisableNoUserInstall (type: boolean, value: true or false, by profile) --deferral-timer-workflow-lastboot=minutes OR DeferralTimerWorkflowLastBoot (type: string, value: number, by profile)

--workflow-disable-no-user-install will prevent any update as long as no GUI user is logged on. if this is enabled, then --deferral-timer-workflow-lastboot will be ignored.

--deferral-timer-workflow-lastboot=minutes defaults to 5 minutes, has a minimum of 2 minutes and a maximum of 60 minutes (higher or lower values will be rounded up or down). It will prevent installation of updates for the given amount of time since the last boot, if no GUI user is logged on.

This does not change the super-starter but runs exit_clean() inside the workflow_no_user_install() function if one of the 2 options applies.

Place the .patch file in the same directory as super and run patch -p1 < super-5.0.0-p3.patch

@Macjutsu You may have a look if this is worth to be included in the project, needs some further changes or whatever. Thank you for all the work on super so far!

super-5.0.0-p3.patch

sch4llfl3g3l avatar Mar 17 '25 14:03 sch4llfl3g3l

Hey folks... my version of this has been partially implemented in https://github.com/Macjutsu/super/releases/tag/v5.1.0-beta2.

While you can't fully disable "no user install" yet (still considering this though), now there is an automatic deferral if the system has recently started up. Further, because there are already too many options in super this is enabled by default and there is a "hard coded" value set by $RECENT_STARTUP_AUTO_DEFERRAL_SECONDS.

Leaving this open b/c I still plan to implement the option to disallow "no user installs".

Macjutsu avatar Mar 17 '25 15:03 Macjutsu

Thanks @Macjutsu would appreciate the ability not to run when no user logged on. It does cause problems for our users.

Oh and glad to see you back. I imagine you are incredibly busy

david-london avatar Mar 20 '25 14:03 david-london