munki / macadmin-scripts

Scripts of possible interest to macOS admins
Other
2.32k stars 524 forks source link

Update installinstallmacos.py with new option to create dmg that's friendly for Jamf Pro deployment purposes #81

Open bp88 opened 3 years ago

bp88 commented 3 years ago

Add an option (--jamf-dmg) to output a compressed read-only dmg that can be used for deployment with Jamf Pro. Jamf Pro can deploy apps through DMGs with a caveat that file structure of the DMG will simply be copied to the target volume. The default --compress option leaves the install macOS app in the root of the DMG which would mean that Jamf Pro would attempt to deploy the app to the root of the target volume which is obviously not desired. Jamf Pro, unlike Munki, is not smart enough to handle seeing an app bundle in the root of a DMG and deploying that to the Applications folder of the target volume.

This change would be particularly helpful given that the "Install macOS Big Sur.app" is too big to be packaged through pkgbuild since the "SharedSupport.dmg" is over 8GB.

gregneagle commented 3 years ago

While the approach you've taken (probably) works now, it's fragile long-term. Instead of deleting things you don't want, it would be better to create a fresh new dmg with the things you do want. Then if Apple changes what gets installed (and installs documentation or a getting-started video, as examples) you don't need to change the script.

bp88 commented 3 years ago

That certainly makes more sense long term. I'll get back to you with an updated pull request and submit it when I get a chance.

bp88 commented 3 years ago

Submitted an update where the script is just grabbing whatever is in the parent folder containing the installer app. Let me know what you think.

gregneagle commented 3 years ago

This still seems rather baroque, and I had to read through the code several times to understand what you were doing and why. More explanatory comments would help.

grahampugh commented 3 years ago

I wonder if this has been obsoleted by https://github.com/scriptingosx/fetch-installer-pkg ? I'm currently incorporating Armin's work into my fork of installinstallmacos.py. Simply a --pkg option. It'll be posted tonight.

gregneagle commented 3 years ago

Obsoleted if all you care about is Big Sur installers, maybe. I have concerns that this doesn't actually grab all the needed components, but too early to tell.

grahampugh commented 3 years ago

Since this only just came up, I assumed that earlier OSes can still be packaged up for uploading to Jamf Pro. Not that I've tried as I don't have any bandwidth issues that would warrant that work.

bp88 commented 3 years ago

I added additional comments in the code block I added. I realize it's longer than the actual code itself but you asked for additional comments in the code.

Here's some further elaboration: The code I've written just makes slight modifications at the end of the code block that basically is used for --compress (the default option). I'm not doing anything drastically different than what the --compress option is already doing as far as simply taking the app bundle and putting it into a dmg. Like I mentioned in the original message, Jamf copies the exact file structure in the DMG onto the target volume so that structure needs to be re-created temporarily in the sparsebundle. The code I've written is simply re-creating that structure.

If we used the resulting DMG we get from --compress, the DMG gives us the file structure of /Install macOS Big Sur.app which would mean that Jamf would try to copy "Install macOS Big Sur.app" to the root of the target volume.

If the file structure in the resulting DMG were /Applications/Install macOS Big Sur.app, Jamf would copy "Install macOS Big Sur.app" to the "Applications folder on the target volume. This is what I'm after with --jamf-dmg.

Because of the way hdiutil works, when you use the find_installer_app() function, it gives you the path to the installer app which means the resulting DMG is basically just a copy of what's in the folder (e.g. "Applications") that contains the installer app.

Don't ask me why but hdiutil treats "folders" and "Installer app bundles" (which I realize are folders) differently. That is, /usr/bin/hdiutil create -fs HFS+ -srcfolder /Applications /path/to/output.dmg results in a DMG where the DMG volume name is "Applications" and in the root of the DMG is only "Install macOS Big Sur.app" vs /usr/bin/hdiutil create -fs HFS+ -srcfolder "/Applications/Install macOS Big Sur.app" /path/to/output.dmg results in a DMG where the DMG volume name is "Install macOS Big Sur" (the ".app" is stripped) and in the root of the DMG is "Install macOS Big Sur.app".

For the purposes of Jamf, we cannot just point hdiutil to installer app bundle which is what the find_installer_app() function is doing since that basically gives us the output we get with --compress.

We also cannot go up one folder in the sparsebundle that's temporarily created because that is in fact just the root of the sparsebundle which contains files that we definitely do not need to deploy. Even the --compress option ignores it.

The --jamf-dmg code is simply taking the parent folder where the app bundle exists (e.g. "Applications") and moving that parent folder to another empty folder in the sparsebundle temporarily so that a compressed dmg can be created so we end up with the proper file structure.

--compress is essentially doing: /usr/bin/hdiutil create -fs HFS+ -srcfolder "../mountpoint/Applications/Install macOS Big Sur.app" diskimagepath and results in a DMG where the DMG volume name is "Install macOS Big Sur" (the ".app" is stripped) and in the root of the DMG is "Install macOS Big Sur.app".

--jamf-dmg is doing: /usr/bin/hdiutil create -fs HFS+ -srcfolder "../mountpoint/Install macOS Big Sur" diskimagepath where "../mountpoint/Install macOS Big Sur/" contains "/Applications/Install macOS Big Sur.app" and results in a DMG where the DMG volume name is "Install macOS Big Sur" (based on the folder name) and in the root of the DMG is "/Applications/Install macOS Big Sur.app".

Does that explain what's going on?

grahampugh commented 3 years ago

Don't forget that with hdiutil you can specify the DMG volume name with -volname. I'm not clear on if the only reason you are copying things around in the sparsebundle is to get the correct DMG name, but just in case...

Also, with that in mind, if I were to use this with Jamf I would want a version or build number in the DMG name to allow for testing and incrementation. Something to also think about if you're trying to avoid subsequent manual steps.

bp88 commented 3 years ago

@grahampugh I did not want to make major modifications to the overall code outside of main(). Since this relies on make_compressed_dmg() and that does not make use of --volname, I had to do what I did to get the friendly volume name. I did consider making that change you're suggesting, but I figured whatever code I contributed had a better chance of getting accepted if there were less modifications made overall to functions outside of main and kept things somewhat isolated. Anyways, I went ahead and made that modification as you suggested. Notice that none of the --jamf-dmg code has any impact on any of the other options that the script takes. I'm submitting new code which has added --volname to make_compressed_dmg().

Keep in mind even with the modification to make_compressed_dmg() to make use of --volname, I would still need to create an empty root directory to move the parent folder of the installer app into. This seems to be what is generating the most confusion. Just need to reiterate here: this is due to the way Jamf supports DMG deployments.

If the concern is the fact that I'm only focusing on the parent folder of the installer app, then that concern should also apply to --compress which as of today only looks at the installer app path.

Also, the resulting DMG file name with --jamf-dmg is the same as the file name you get with --compress which already includes the OS version and build. My proposed code doesn't change the file name of the resulting DMG.

bp88 commented 3 years ago

Just checking in. Have the last changes I made satisfied the concerns that were raised?

bp88 commented 3 years ago

@gregneagle Just wanted to check in again. Have the changes I made satisfied the concerns that you had raised?