class Macinbox::Actions::CreateImageFromInstaller
Public Class Methods
new(opts)
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 16 def initialize(opts) @installer_app = opts[:installer_path] or raise ArgumentError.new(":installer_path not specified") @output_path = opts[:image_path] or raise ArgumentError.new(":image_path not specified") @vmware_fusion_app = opts[:vmware_path] @parallels_app = opts[:parallels_path] @user_script = opts[:user_script] @disk_size = opts[:disk_size] or raise ArgumentError.new(":disk_size not specified") @fstype = opts[:fstype] or raise ArgumentError.new(":fstype not specified") @short_name = opts[:short_name] or raise ArgumentError.new(":short_name not specified") @full_name = opts[:full_name] or raise ArgumentError.new(":full_name not specified") @password = opts[:password] or raise ArgumentError.new(":password not specified") @box_format = opts[:box_format] @auto_login = opts[:auto_login] @skip_mini_buddy = opts[:skip_mini_buddy] @hidpi = opts[:hidpi] @collector = opts[:collector] or raise ArgumentError.new(":collector not specified") raise Macinbox::Error.new("Installer app not found") unless File.exist? @installer_app raise ArgumentError.new(":vmware_path not specified") if @box_format == "vmware_desktop" && !opts[:vmware_path] raise ArgumentError.new(":parallels_path not specified") if @box_format == "parallels" && !opts[:parallels_path] end
Public Instance Methods
automate_user_account_creation()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 138 def automate_user_account_creation Logger.info "Configuring the primary user account..." do scratch_installer_configuration_file = "#{@scratch_mountpoint}/private/var/db/.InstallerConfiguration" File.write scratch_installer_configuration_file, <<~EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Users</key> <array> <dict> <key>admin</key> <true/> <key>autologin</key> <#{@auto_login ? true : false}/> <key>fullName</key> <string>#{@full_name}</string> <key>shortName</key> <string>#{@short_name}</string> <key>password</key> <string>#{@password}</string> <key>skipMiniBuddy</key> <#{@skip_mini_buddy ? true : false}/> </dict> </array> </dict> </plist> EOF end end
automate_vagrant_group_creation()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 169 def automate_vagrant_group_creation if @short_name == "vagrant" Logger.info "Configuring the 'vagrant' group..." do contents = <<~EOF until dscl . -read /Users/vagrant UniqueID; do sleep 1 done dscl . -create /Groups/vagrant dscl . -create /Groups/vagrant gid 501 dscl . -create /Groups/vagrant GroupMembers `dscl . -read /Users/vagrant GeneratedUID | cut -d ' ' -f 2` dscl . -create /Groups/vagrant GroupMembership vagrant EOF File.write @scratch_rc_vagrant, contents, mode: 'a' end end end
automate_vagrant_ssh_key_installation()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 186 def automate_vagrant_ssh_key_installation if @short_name == "vagrant" Logger.info "Installing the default insecure vagrant ssh key..." do contents = <<~EOF while [ ! -e /Users/vagrant ]; do sleep 1 done while [ `stat -f %u /Users/vagrant` == 0 ]; do sleep 1 done if [ ! -e /Users/vagrant/.ssh ]; then mkdir /Users/vagrant/.ssh chmod 0700 /Users/vagrant/.ssh chown `stat -f %u /Users/vagrant` /Users/vagrant/.ssh fi echo "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key" >> /Users/vagrant/.ssh/authorized_keys chmod 0600 /Users/vagrant/.ssh/authorized_keys chown `stat -f %u /Users/vagrant` /Users/vagrant/.ssh/authorized_keys EOF File.write @scratch_rc_vagrant, contents, mode: 'a' end end end
create_rc_vagrant()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 110 def create_rc_vagrant first_boot_launch_daemon = "#{@scratch_mountpoint}/Library/LaunchDaemons/rc.vagrant.plist" File.write first_boot_launch_daemon, <<~EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>rc.vagrant</string> <key>ProgramArguments</key> <array> <string>/etc/rc.vagrant</string> </array> <key>RunAtLoad</key> <true/> </dict> </plist> EOF FileUtils.chmod 0755, first_boot_launch_daemon @scratch_rc_vagrant = "#{@scratch_mountpoint}/private/etc/rc.vagrant" File.write @scratch_rc_vagrant, <<~EOF #!/bin/sh rm -r /Library/LaunchDaemons/rc.vagrant.plist rm -f /etc/rc.vagrant EOF FileUtils.chmod 0755, @scratch_rc_vagrant end
create_scratch_image()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 83 def create_scratch_image Logger.info "Creating and attaching a new blank disk image..." do @scratch_image = "#{@temp_dir}/scratch.sparseimage" @scratch_disk = VirtualDisk.new(@scratch_image) @collector.on_cleanup { @scratch_disk.detach! } @scratch_mountpoint = "#{@temp_dir}/scratch_mountpoint" FileUtils.mkdir @scratch_mountpoint @scratch_disk.create(@disk_size, @fstype) @scratch_disk.attach @scratch_disk.mount(at: @scratch_mountpoint, owners: true) end end
create_temp_dir()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 60 def create_temp_dir @temp_dir = Task.backtick %W[ /usr/bin/mktemp -d -t create_image_from_installer ] @collector.add_temp_dir @temp_dir end
create_wrapper_image()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 71 def create_wrapper_image Logger.info "Creating and attaching wrapper disk image..." do @wrapper_image = "#{@temp_dir}/wrapper.dmg" @wrapper_disk = VirtualDisk.new(@wrapper_image) @collector.on_cleanup { @wrapper_disk.detach! } @wrapper_disk.create_from_folder(@installer_app) @wrapper_disk.attach @wrapper_disk.mount @installer_app = "#{@wrapper_disk.mountpoint}/#{File.basename @installer_app}" end end
enable_hidpi()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 228 def enable_hidpi if @hidpi Logger.info "Enabling HiDPI resolutions..." do scratch_windowserver_preferences = "#{@scratch_mountpoint}/Library/Preferences/com.apple.windowserver.plist" File.write scratch_windowserver_preferences, <<~EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>DisplayResolutionEnabled</key> <true/> </dict> </plist> EOF end end end
enable_passwordless_sudo()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 210 def enable_passwordless_sudo Logger.info "Enabling password-less sudo..." do scratch_sudoers_d_user_rule_file = "#{@scratch_mountpoint}/private/etc/sudoers.d/#{@short_name}" File.write scratch_sudoers_d_user_rule_file, <<~EOF #{@short_name} ALL=(ALL) NOPASSWD: ALL EOF FileUtils.chmod 0440, scratch_sudoers_d_user_rule_file end end
enable_sshd()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 220 def enable_sshd Logger.info "Enabling sshd..." do scratch_launchd_disabled_plist = "#{@scratch_mountpoint}/private/var/db/com.apple.xpc.launchd/disabled.plist" opts = $verbose ? {} : { :out => File::NULL } Task.run %W[ /usr/libexec/PlistBuddy -c #{'Add :com.openssh.sshd bool False'} #{scratch_launchd_disabled_plist} ] + [opts] end end
install_macos()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 96 def install_macos Logger.info "Installing macOS..." do activity = Logger.prefix + "installer" install_info_plist = "#{@installer_app}/Contents/SharedSupport/InstallInfo.plist" Task.run %W[ /usr/bin/touch #{@scratch_mountpoint}/.macinbox ] cmd = %W[ /usr/sbin/installer -verboseR -dumplog -pkg #{install_info_plist} -target #{@scratch_mountpoint} ] opts = $verbose ? {} : { :err => [:child, :out] } Task.run_with_progress activity, cmd, opts do |line| /^installer:%(.*)$/.match(line)[1].to_f rescue nil end @wrapper_disk.detach! if @wrapper_disk end end
installer_is_on_root_filesystem()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 65 def installer_is_on_root_filesystem root_device = Task.backtick %W[ /usr/bin/stat -f %d / ] installer_device = Task.backtick %W[ /usr/bin/stat -f %d #{@installer_app} ] root_device == installer_device end
run()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 42 def run create_temp_dir if installer_is_on_root_filesystem create_wrapper_image end create_scratch_image install_macos create_rc_vagrant automate_user_account_creation automate_vagrant_group_creation automate_vagrant_ssh_key_installation enable_passwordless_sudo enable_sshd enable_hidpi run_user_script save_image end
run_user_script()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 246 def run_user_script if @user_script Logger.info "Running user script..." do Task.run %W[ #{@user_script} #{@scratch_mountpoint} ] end end end
save_image()
click to toggle source
# File lib/macinbox/actions/create_image_from_installer.rb, line 254 def save_image Logger.info "Saving the image..." do @scratch_disk.eject FileUtils.chown ENV["SUDO_USER"], nil, @scratch_image FileUtils.mv @scratch_image, @output_path end end