(#19162) Execute shutdown command after puppet exits

Previously, there was a race condition between the time that puppet exited and
when the OS rebooted the system. This is because we were requesting a shutdown
(reboot) in `timeout` seconds, but puppet sends a report, which is processed
synchronously by the master. So it was possible for puppet to still be running
when the OS reboots the system.

This commit creates a Watcher class whose job is to wait for the puppet process
to complete, and then execute a command at the end.